3 Commits

Author SHA1 Message Date
宋杰 1fd9806f47 宋杰4.29页面整合完成 3 weeks ago
宋杰 a55a800e50 Merge branch 'songjie' into dev 3 weeks ago
guoyanqiang 8c81241998 gyq_huodong_4.28 3 weeks ago
  1. 112
      package-lock.json
  2. 3
      package.json
  3. 15
      src/App.vue
  4. 14
      src/api/axiosConfig.js
  5. BIN
      src/assets/images/日历.png
  6. 32
      src/main.js
  7. 10
      src/router/index.js
  8. 10
      src/views/ActivityManagement.vue
  9. 582
      src/views/VotingManagement.vue

112
package-lock.json

@ -14,7 +14,8 @@
"moment": "^2.30.1",
"pinia": "^3.0.1",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
"vue-router": "^4.5.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.3",
@ -1705,6 +1706,15 @@
}
}
},
"node_modules/adler-32": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/async-validator": {
"version": "4.2.5",
"resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
@ -1820,6 +1830,28 @@
],
"license": "CC-BY-4.0"
},
"node_modules/cfb": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"crc-32": "~1.2.0"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/codepage": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -1854,6 +1886,18 @@
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"license": "Apache-2.0",
"bin": {
"crc32": "bin/crc32.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@ -1973,9 +2017,9 @@
"license": "ISC"
},
"node_modules/element-plus": {
"version": "2.9.8",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.8.tgz",
"integrity": "sha512-srViUaUdfblBKGMeuEPiXxxKlH5aUmKqEwmhb/At9Sj91DbU6od/jYN1955cTnzt3wTSA7GfnZF7UiRX9sdRHg==",
"version": "2.9.9",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.9.tgz",
"integrity": "sha512-gN553+xr7ETkhJhH26YG0fERmd2BSCcQKslbtR8fats0Mc0yCtZOXr00bmoPOt5xGzhuRN1TWc9+f1pCaiA0/Q==",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "^3.4.1",
@ -2221,6 +2265,15 @@
"node": ">= 6"
}
},
"node_modules/frac": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/fs-extra": {
"version": "11.3.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
@ -3024,6 +3077,18 @@
"node": ">=0.10.0"
}
},
"node_modules/ssf": {
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
"license": "Apache-2.0",
"dependencies": {
"frac": "~1.1.2"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/strip-final-newline": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
@ -3351,6 +3416,45 @@
"node": ">= 8"
}
},
"node_modules/wmf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/word": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz",
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/xlsx": {
"version": "0.18.5",
"resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"cfb": "~1.2.1",
"codepage": "~1.15.0",
"crc-32": "~1.2.1",
"ssf": "~0.11.2",
"wmf": "~1.0.1",
"word": "~0.3.0"
},
"bin": {
"xlsx": "bin/xlsx.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",

3
package.json

@ -15,7 +15,8 @@
"moment": "^2.30.1",
"pinia": "^3.0.1",
"vue": "^3.5.13",
"vue-router": "^4.5.0"
"vue-router": "^4.5.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.3",

15
src/App.vue

@ -1,13 +1,18 @@
<template>
<RouterView/>
<!-- <div id="app">
<voting-management></voting-management>
</div> -->
<router-view></router-view>
</template>
<script setup>
import { RouterView } from 'vue-router';
<script>
// export default {
// name: 'App',
// };
</script>
<style scoped>
<style>
/* 添加全局样式 */
</style>

14
src/api/axiosConfig.js

@ -0,0 +1,14 @@
import axios from 'axios';
const instance = axios.create({
baseURL: 'http://192.168.8.235:8000/api/vote', // 后端 API 基地址
timeout: 3000,
});
export default instance;

BIN
src/assets/images/日历.png

After

Width: 200  |  Height: 200  |  Size: 5.0 KiB

32
src/main.js

@ -1,28 +1,28 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
import { createApp } from 'vue' // 引入vue实例
import App from './App.vue' // 引入App.vue
import router from './router' // 引入router
import axios from './api/axiosConfig'; // 引入axiosConfig
import VotingManagement from './views/VotingManagement.vue' // 引入VotingManagement.vue
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'
import { createPinia } from 'pinia'
const app = createApp(App) // 创建vue实例
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
app.component(key, component)
}
app.use(ElementPlus, {
locale: zhCn,
})
app.component('VotingManagement', VotingManagement) // 注册组件
app.config.globalProperties.axios = axios; // 全局挂载axios
app.use(ElementPlus, {
locale: zhCn,
})
app.use(createPinia())
app.use(router)
app.use(ElementPlus)

10
src/router/index.js

@ -1,5 +1,6 @@
import { createRouter, createWebHistory } from 'vue-router'
import ActivityManagement from '@/views/ActivityManagement.vue'
import VotingManagement from '@/views/VotingManagement.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
@ -9,7 +10,12 @@ const router = createRouter({
name: 'activityManagement',
component: ActivityManagement,
},
],
})
{
path: '/vote/:id',
name: 'votingManagement',
component: VotingManagement,
},
]
});
export default router

10
src/views/ActivityManagement.vue

@ -35,7 +35,7 @@
<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>
<el-button size="mini" type="primary" @click="viewDetails(scope.row.id)">查看详情</el-button>
</div>
</template>
</el-table-column>
@ -100,7 +100,7 @@ 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';
import router from '@/router';
function indexMethod(index){
return itemsPerPage*(currentPage.value-1)+index+1;
@ -182,8 +182,10 @@ const editActivity = (activity) => {
};
//
const viewDetails = (activity) => {
ElMessage.info(`活动ID: ${activity.id}, 活动标题: ${activity.title}, 日期: ${activity.start} - ${activity.end}, 访问人数: ${activity.visit_count}`);
const viewDetails = (id) => {
console.log(id);
router.push({ name: 'votingManagement', params: { id: id } });
// ElMessage.info(`ID: ${activity.id}, : ${activity.title}, : ${activity.start} - ${activity.end}, 访: ${activity.visit_count}`);
};
const handlePictureCardPreview = (file) => {

582
src/views/VotingManagement.vue

@ -0,0 +1,582 @@
<template>
<div class="container">
<!-- 左侧菜单栏 -->
<div class="sidebar">
<ul class="menu">
<li class="menu-item active">投票管理</li>
<li class="menu-item">盲盒管理</li>
<li class="menu-item">大转盘管理</li>
</ul>
</div>
<!-- 主内容区域 -->
<div class="main-content">
<!-- 页面头部 -->
<header class="header">
<div class="header-title">活动管理后台</div>
</header>
<div class="content-container">
<!-- 卡片容器 -->
<div class="card">
<div class="card-header">
<span class="card-title">查看详情</span>
<button class="back-btn" @click="goBack">返回上一页</button>
</div>
<!-- 搜索按钮区域 -->
<div class="search-bar">
<div class="search-input-area">
<input type="text" class="search-input" placeholder="请输入精网号" v-model="searchId">
<div class="dropdown">
<select class="region-select" v-model="selectedRegion">
<option value="">请选择地区</option>
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="香港">香港</option>
</select>
</div>
<div class="date-range">
<div class="date-picker">
<img src="../assets/images/日历.png" alt="Calendar"
class="calendar-icon">
<input type="date" class="date-input" placeholder="开始日期" v-model="startDate">
</div>
<span class="date-separator"></span>
<div class="date-picker">
<img src="../assets/images/日历.png" alt="Calendar"
class="calendar-icon">
<input type="date" class="date-input" placeholder="结束日期" v-model="endDate">
</div>
</div>
</div>
<div class="search-buttons">
<button class="search-btn" @click="searchVoteRecords">搜索</button>
<button class="export-btn" @click="exportExcel">导出Excel</button>
</div>
</div>
<!-- 表格数据展示 -->
<div class="table-container">
<table class="data-table">
<thead>
<tr>
<th>序号</th>
<th>姓名</th>
<th>精网号</th>
<th>地区</th>
<th>投票明细</th>
<th>投票时间</th>
</tr>
</thead>
<tbody>
<tr v-for="(record, index) in voteRecords" :key="index">
<td>{{ index + 1 }}</td>
<td>{{ record.nickname }}</td>
<td>{{ record.jwcode }}</td>
<td>{{ record.dept }}</td>
<td>{{ record.options_title }}</td>
<td>{{ record.time }}</td>
</tr>
</tbody>
</table>
</div>
<!-- 分页 -->
<el-pagination class="pagination" v-model:current-page="currentPage" v-model:page-size="pageSize" :page-sizes="[5, 10, 20]"
:total="totalPages" @size-change="handleSizeChange" @current-change="handlePageChange"
layout="total, sizes, prev, pager, next, jumper" />
<!-- <div class="pagination">
<div class="pagination-info"> {{ currentPage }} </div>
<div class="page-size">
<select class="page-size-select" v-model="pageSize">
<option value="8">8/</option>
</select>
</div>
<div class="page-numbers">
<button class="page-btn" @click="changePage(currentPage - 1)" :disabled="currentPage === 1">&lt;</button>
<button class="page-btn" v-for="page in totalPages" :key="page" @click="changePage(page)":class="{ active: page === currentPage }">{{ page }}</button>
<button class="page-btn" @click="changePage(currentPage + 1)":disabled="currentPage === totalPages">&gt;</button>
</div>
<div class="go-to-page">
<span>前往第</span>
<input type="number" class="page-input" v-model.number="currentPage" @change="changePage(currentPage)"
min="1" :max="totalPages">
<span></span>
</div>
</div> -->
</div>
</div>
</div>
</div>
</template>
<script>
import { ref } from 'vue';
import axiosInstance from '@/api/axiosConfig';
import axiosexport from '@/api/axiosConfig';
import { ElTable } from 'element-plus';
import { useRoute } from 'vue-router';
export default {
//
data() {
return {
// detailId: window.location.pathname.split('/').pop() || '24',
detailId: ref(0),
//detailId: 24,
searchId: '',
selectedRegion: '',
startDate: '',
endDate: '',
// currentPage: 1,
// pageSize: 8,
voteRecords: {},
totalPages: ref(0),
totalRecords: 0,
currentPage: ref(1),
pageSize: ref(10),
route: useRoute(),
};
},
methods: {
// current-change
handlePageChange(val) {
console.log(`current page: ${val}`);
this.fetchVoteRecords(); //
},
handleSizeChange(val) {
this.fetchVoteRecords();
},
//
async fetchVoteRecords(detailId) {
try {
const params = {
PageNo: this.currentPage,
PageSize: this.pageSize,
ActivityId: this.detailId,
};
const response = await axiosInstance.post('', params);
this.voteRecords = response.data.data.list;
this.totalPages = response.data.data.total;
console.log(response.data.data.list);
// this.totalRecords = response.data.data.total;
} catch (error) {
console.error('获取投票记录失败:', error);
}
},
//
async searchVoteRecords() {
try {
const params = {
jwcode: this.searchId,
dept: this.selectedRegion,
startDate: this.startDate,
endDate: this.endDate,
PageNo: this.currentPage,
PageSize: this.pageSize,
ActivityId: this.detailId,
};
const response = await axiosInstance.post('', params);
this.voteRecords = response.data.data.list;
this.totalRecords = response.data.data.total;
this.currentPage = 1;
this.totalPages = Math.ceil(this.totalRecords / this.pageSize);
} catch (error) {
console.error('搜索投票记录失败:', error);
}
},
// Excel
async exportExcel() {
try {
//
const params = {
jwcode: this.searchId,
dept: this.selectedRegion,
startDate: this.startDate,
endDate: this.endDate,
ActivityId: this.detailId
};
// POST blob
const response = await axiosInstance.post('http://192.168.8.235:8000/api/export', params, {
responseType: 'blob'
});
// Blob URL
const url = window.URL.createObjectURL(new Blob([response.data]));
// <a>
const link = document.createElement('a');
link.href = url;
//
link.setAttribute('download', '投票记录.xlsx');
document.body.appendChild(link);
//
link.click();
// URL
window.URL.revokeObjectURL(url);
// <a>
document.body.removeChild(link);
} catch (error) {
console.error('导出 Excel 失败:', error);
// 使 Element Plus
// ElMessage.error(' Excel ');
}
},
//
// changePage(page) {
// if (page >= 1 && page <= this.totalPages) {
// this.currentPage = page;
// this.fetchVoteRecords();
// }
// },
//
goBack() {
window.history.back();
},
},
//
mounted() {
this.detailId = this.route.params.id;
console.log(this.route.params.id);
console.log(this.detailId);
this.fetchVoteRecords(this.detailId);
}
};
</script>
<style scoped>
/* 全局容器样式 */
.container {
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
width: 100%;
height: 100vh;
background-color: #f5f5f5;
display: flex;
flex-direction: row;
}
/* 左侧菜单栏样式 */
.sidebar {
width: 9%;
height: 85.5%;
background-color: #fff;
padding: 0.5% 0;
box-shadow: 3px 0 4px rgba(0, 0, 0, 0.05);
margin-top: 5.6rem;
margin-left: 1.6%;
}
.menu {
list-style: none;
padding: 0;
margin: 0;
}
.menu-item {
padding: 1rem 2.4rem;
cursor: pointer;
color: #666;
transition: background-color 0.3s;
}
.menu-item:hover {
background-color: #e6e6e6;
}
.menu-item.active {
background-color: #fff;
color: #ff6b6b;
font-weight: bold;
border-left: 3px solid #ff6b6b;
}
/* 主内容区域样式 */
.main-content {
flex: 1;
display: flex;
flex-direction: column;
}
/* 页面头部样式 */
.header {
display: flex;
justify-content: space-between;
align-items: center;
height: 4.7rem;
padding: 0 12.5rem;
background-color: #fff;
box-shadow: 0 5px 4px rgba(0, 0, 0, 0.05);
margin-left: -16rem;
}
.header-title {
font-size: 23px;
/* font-weight: bold; */
color: #333;
margin-top: -0.3rem;
}
/* 内容容器样式 */
.content-container {
flex: 1;
padding: 20px;
}
/* 卡片样式 */
.card {
width: 96%;
height: 100%;
background-color: #fff;
/* box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); */
box-shadow: 1px 5px 8px rgba(0, 0, 0, 0.05);
overflow: hidden;
margin-top: -0.3%;
}
/* 卡片头部样式 */
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
border-bottom: 1px solid #eee;
}
.card-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-left: 1rem;
}
.back-btn {
padding: 6px 12px;
border: 1px solid #e75d5d;
border-radius: 4px;
background-color: #fff;
color: #e75d5d;
font-size: 14px;
cursor: pointer;
margin-right: 2rem;
}
/* 搜索框区域样式 */
.search-bar {
padding: 20px;
background-color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
}
.search-input-area {
display: flex;
align-items: center;
gap: 18px;
}
.search-input {
width: 8rem;
padding: 8px 12px;
border: 2px solid #ddd;
border-radius: 7px;
font-size: 14px;
}
.region-select {
width: 9rem;
padding: 8px 12px;
border: 2px solid #ddd;
border-radius: 7px;
font-size: 14px;
color: #999;
/* 设置输入框内文字颜色 */
}
.date-range {
display: flex;
align-items: center;
gap: 10px;
}
.date-picker {
position: relative;
display: flex;
align-items: center;
}
.calendar-icon {
width: 14%;
position: absolute;
left: 8px;
top: 49%;
transform: translateY(-50%);
color: #999;
}
.date-input {
padding: 8px 12px 8px 28px;
border: 2px solid #ddd;
border-radius: 7px;
font-size: 14px;
color: #999;
/* 设置输入框内文字颜色 */
}
.date-separator {
margin: 0 10px;
color: #666;
}
.search-buttons {
display: flex;
gap: 5px;
margin-right: 38rem;
}
.search-btn,
.export-btn {
padding: 9px 20px;
border: none;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
/* margin-right: 19.3rem; */
}
.search-btn {
background-color: #e63946;
color: #fff;
}
.export-btn {
background-color: #e63946;
color: #fff;
/* margin-right: 20rem; */
}
/* 表格区域样式 */
.table-container {
padding: 3px 13px;
}
.data-table {
width: 100%;
border-collapse: collapse;
}
.data-table th {
padding: 15px;
text-align: center;
background-color: #f5f5f5;
font-weight: normal;
color: #666;
border-bottom: 1px solid #ddd;
}
.data-table td {
padding: 14px 16px;
text-align: center;
border-bottom: 2px solid #eee;
font-size: 15px;
}
.even-row {
background-color: #fff;
}
.odd-row {
background-color: #fff;
}
/* 分页区域样式 */
.pagination {
width: 10%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px 20px;
border-top: 1px solid #eee;
margin-top: 2.2rem;
margin-left: 65rem;
}
.pagination-info {
font-size: 14px;
color: #666;
font-weight: bold;
margin-left: 45rem;
}
.page-size {
margin-left: -11rem;
}
.page-size-select {
padding: 5px 12px;
border: 2px solid #ddd;
font-size: 14px;
}
.page-numbers {
display: flex;
align-items: center;
gap: 0px;
margin-left: -6rem;
}
.page-btn {
width: 1.5rem;
display: flex;
justify-content: center;
align-items: center;
border: 0px solid #ddd;
background-color: #fff;
cursor: pointer;
font-size: 15px;
}
.page-btn.active {
background-color: #f0f0f0;
font-weight: bold;
}
.go-to-page {
display: flex;
align-items: center;
gap: 5px;
font-size: 14px;
}
.page-input {
width: 40px;
padding: 5px 4px;
border: 2px solid #ddd;
border-radius: 4px;
text-align: center;
font-size: 14px;
}
</style>
Loading…
Cancel
Save