社团统计及团员统计
This commit is contained in:
@@ -64,12 +64,19 @@
|
||||
学生社团列表
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="Plus"
|
||||
type="primary"
|
||||
<el-button
|
||||
icon="Plus"
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog()">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="DataAnalysis"
|
||||
type="warning"
|
||||
class="ml10"
|
||||
@click="handleStats">
|
||||
社团统计
|
||||
</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
class="ml10"
|
||||
@@ -187,9 +194,54 @@
|
||||
|
||||
<!-- 新增/编辑表单弹窗 -->
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList" />
|
||||
|
||||
|
||||
<!-- 查看成员弹窗 -->
|
||||
<member-dialog ref="memberDialogRef" />
|
||||
|
||||
<!-- 社团统计弹窗 -->
|
||||
<el-dialog
|
||||
title="社团统计"
|
||||
v-model="statsDialogVisible"
|
||||
:width="700"
|
||||
:close-on-click-modal="false"
|
||||
draggable>
|
||||
<el-table
|
||||
:data="statsData"
|
||||
v-loading="statsLoading"
|
||||
stripe
|
||||
border
|
||||
max-height="400">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="deptName" label="学院名称" align="center" min-width="150" />
|
||||
<el-table-column prop="associationCount" label="社团数量" align="center" width="120">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.associationCount > 0 ? 'success' : 'info'" effect="plain">
|
||||
{{ scope.row.associationCount }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<!-- 统计汇总 -->
|
||||
<div v-if="statsData.length > 0" class="stats-summary">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="summary-item">
|
||||
<span class="label">学院总数:</span>
|
||||
<span class="value">{{ statsData.length }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="summary-item">
|
||||
<span class="label">社团总数:</span>
|
||||
<span class="value highlight">{{ totalAssociationCount }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="statsDialogVisible = false">关 闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -197,7 +249,7 @@
|
||||
import { reactive, ref, onMounted, computed, nextTick } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObj } from "/@/api/stuwork/stuassociation";
|
||||
import { fetchList, delObj, getAssociationStats } from "/@/api/stuwork/stuassociation";
|
||||
import { getDeptList } from "/@/api/basic/basicclass";
|
||||
import { getDicts } from "/@/api/admin/dict";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
@@ -205,9 +257,9 @@ import { parseTime } from "/@/utils/formatTime";
|
||||
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
|
||||
import FormDialog from './form.vue'
|
||||
import MemberDialog from './member.vue'
|
||||
import {
|
||||
List, Trophy, OfficeBuilding, User, UserFilled, Calendar,
|
||||
Phone, Collection, Document, Files, Setting, Menu, Search
|
||||
import {
|
||||
List, Trophy, OfficeBuilding, User, UserFilled, Calendar,
|
||||
Phone, Collection, Document, Files, Setting, Menu, Search, DataAnalysis
|
||||
} from '@element-plus/icons-vue'
|
||||
import { useTableColumnControl } from '/@/hooks/tableColumn'
|
||||
|
||||
@@ -222,6 +274,11 @@ const showSearch = ref(true)
|
||||
const deptList = ref<any[]>([])
|
||||
const typeList = ref<any[]>([])
|
||||
|
||||
// 社团统计相关
|
||||
const statsDialogVisible = ref(false)
|
||||
const statsLoading = ref(false)
|
||||
const statsData = ref<any[]>([])
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = [
|
||||
{ prop: 'associationName', label: '社团名称', minWidth: 200 },
|
||||
@@ -362,6 +419,31 @@ const getTypeDict = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 社团统计
|
||||
const handleStats = async () => {
|
||||
statsDialogVisible.value = true
|
||||
statsLoading.value = true
|
||||
statsData.value = []
|
||||
try {
|
||||
const res = await getAssociationStats()
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
statsData.value = res.data
|
||||
} else {
|
||||
statsData.value = []
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取统计数据失败')
|
||||
statsData.value = []
|
||||
} finally {
|
||||
statsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 社团总数计算
|
||||
const totalAssociationCount = computed(() => {
|
||||
return statsData.value.reduce((sum, item) => sum + (item.associationCount || 0), 0)
|
||||
})
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
getDeptListData()
|
||||
@@ -375,5 +457,32 @@ onMounted(() => {
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '/@/assets/styles/modern-page.scss';
|
||||
|
||||
.stats-summary {
|
||||
margin-top: 15px;
|
||||
padding: 15px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 4px;
|
||||
|
||||
.summary-item {
|
||||
text-align: center;
|
||||
|
||||
.label {
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-left: 5px;
|
||||
color: #409eff;
|
||||
|
||||
&.highlight {
|
||||
color: #67c23a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -103,6 +103,10 @@
|
||||
毕业学生名单
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button type="primary" icon="DataAnalysis" @click="handleConfirmScore">学分确认</el-button>
|
||||
<el-button type="success" icon="DataAnalysis" @click="handleConfirmConduct">操行确认</el-button>
|
||||
<el-button type="warning" icon="DataAnalysis" @click="handleConfirmPunish">违纪确认</el-button>
|
||||
<el-button type="info" icon="DataAnalysis" @click="handleConfirmSkill">等级工确认</el-button>
|
||||
<right-toolbar
|
||||
v-model:showSearch="showSearch"
|
||||
class="ml10"
|
||||
@@ -181,6 +185,61 @@
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 确认结果对话框 -->
|
||||
<el-dialog
|
||||
v-model="confirmDialogVisible"
|
||||
:title="confirmTypeLabel"
|
||||
width="800px"
|
||||
destroy-on-close>
|
||||
<div v-loading="confirmLoading">
|
||||
<!-- 统计信息 -->
|
||||
<el-row :gutter="20" class="confirm-stats">
|
||||
<el-col :span="6">
|
||||
<el-statistic title="总人数" :value="confirmResult.totalCount || 0">
|
||||
<template #suffix>
|
||||
<span style="font-size: 12px; color: #909399;">人</span>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-statistic title="合格人数" :value="confirmResult.qualifiedCount || 0">
|
||||
<template #suffix>
|
||||
<span style="font-size: 12px; color: #67c23a;">人</span>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-statistic title="不合格人数" :value="confirmResult.unqualifiedCount || 0">
|
||||
<template #suffix>
|
||||
<span style="font-size: 12px; color: #f56c6c;">人</span>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-divider content-position="left">不合格学生列表</el-divider>
|
||||
|
||||
<!-- 不合格学生表格 -->
|
||||
<el-table
|
||||
:data="confirmResult.unqualifiedList || []"
|
||||
stripe
|
||||
max-height="350px"
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle">
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="stuNo" label="学号" align="center" width="120" />
|
||||
<el-table-column prop="realName" label="姓名" align="center" width="100" />
|
||||
<el-table-column prop="classNo" label="班号" align="center" width="120" />
|
||||
<el-table-column prop="reason" label="不合格原因" align="center" min-width="150" />
|
||||
<el-table-column prop="detail" label="详情" align="center" min-width="150" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="confirmDialogVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -188,7 +247,7 @@
|
||||
import { reactive, ref, computed, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { BasicTableProps, useTable } from '/@/hooks/table'
|
||||
import { fetchList } from '/@/api/stuwork/stugraducheck'
|
||||
import { fetchList, confirmScore, confirmConduct, confirmPunish, confirmSkill } from '/@/api/stuwork/stugraducheck'
|
||||
import { getDeptList } from '/@/api/basic/basicclass'
|
||||
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
|
||||
import {
|
||||
@@ -198,9 +257,11 @@ import {
|
||||
Document,
|
||||
Menu,
|
||||
Search,
|
||||
Grid
|
||||
Grid,
|
||||
DataAnalysis
|
||||
} from '@element-plus/icons-vue'
|
||||
import { useTableColumnControl } from '/@/hooks/tableColumn'
|
||||
import { useMessage } from '/@/hooks/message'
|
||||
|
||||
const route = useRoute()
|
||||
const searchFormRef = ref()
|
||||
@@ -208,6 +269,26 @@ const columnControlRef = ref<any>()
|
||||
const showSearch = ref(true)
|
||||
const deptList = ref<any[]>([])
|
||||
|
||||
// 确认对话框相关变量
|
||||
const confirmDialogVisible = ref(false)
|
||||
const confirmLoading = ref(false)
|
||||
const confirmResult = ref<any>({
|
||||
confirmType: '',
|
||||
totalCount: 0,
|
||||
qualifiedCount: 0,
|
||||
unqualifiedCount: 0,
|
||||
unqualifiedList: []
|
||||
})
|
||||
const confirmTypeLabel = computed(() => {
|
||||
const map: Record<string, string> = {
|
||||
score: '学分确认',
|
||||
conduct: '操行确认',
|
||||
punish: '违纪确认',
|
||||
skill: '等级工确认'
|
||||
}
|
||||
return map[confirmResult.value.confirmType] || '确认结果'
|
||||
})
|
||||
|
||||
// 毕业年份:当前年前后各 5 年
|
||||
const graduYearOptions = computed(() => {
|
||||
const y = new Date().getFullYear()
|
||||
@@ -299,6 +380,86 @@ const loadDeptList = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 学分确认
|
||||
const handleConfirmScore = async () => {
|
||||
if (!searchForm.graduYear) {
|
||||
useMessage().warning('请先选择毕业年份')
|
||||
return
|
||||
}
|
||||
confirmLoading.value = true
|
||||
confirmDialogVisible.value = true
|
||||
try {
|
||||
const res = await confirmScore(searchForm.graduYear)
|
||||
if (res.data) {
|
||||
confirmResult.value = res.data
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '学分确认失败')
|
||||
} finally {
|
||||
confirmLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 操行确认
|
||||
const handleConfirmConduct = async () => {
|
||||
if (!searchForm.graduYear) {
|
||||
useMessage().warning('请先选择毕业年份')
|
||||
return
|
||||
}
|
||||
confirmLoading.value = true
|
||||
confirmDialogVisible.value = true
|
||||
try {
|
||||
const res = await confirmConduct(searchForm.graduYear)
|
||||
if (res.data) {
|
||||
confirmResult.value = res.data
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '操行确认失败')
|
||||
} finally {
|
||||
confirmLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 违纪确认
|
||||
const handleConfirmPunish = async () => {
|
||||
if (!searchForm.graduYear) {
|
||||
useMessage().warning('请先选择毕业年份')
|
||||
return
|
||||
}
|
||||
confirmLoading.value = true
|
||||
confirmDialogVisible.value = true
|
||||
try {
|
||||
const res = await confirmPunish(searchForm.graduYear)
|
||||
if (res.data) {
|
||||
confirmResult.value = res.data
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '违纪确认失败')
|
||||
} finally {
|
||||
confirmLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 等级工确认
|
||||
const handleConfirmSkill = async () => {
|
||||
if (!searchForm.graduYear) {
|
||||
useMessage().warning('请先选择毕业年份')
|
||||
return
|
||||
}
|
||||
confirmLoading.value = true
|
||||
confirmDialogVisible.value = true
|
||||
try {
|
||||
const res = await confirmSkill(searchForm.graduYear)
|
||||
if (res.data) {
|
||||
confirmResult.value = res.data
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '等级工确认失败')
|
||||
} finally {
|
||||
confirmLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadDeptList()
|
||||
})
|
||||
|
||||
@@ -78,23 +78,29 @@
|
||||
学生团组织列表
|
||||
</span>
|
||||
<div class="header-actions">
|
||||
<el-button
|
||||
icon="Plus"
|
||||
type="primary"
|
||||
<el-button
|
||||
icon="DataAnalysis"
|
||||
type="info"
|
||||
@click="handleStatistics">
|
||||
团员统计
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Plus"
|
||||
type="primary"
|
||||
@click="formDialogRef.openDialog()">
|
||||
新增
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Upload"
|
||||
type="success"
|
||||
class="ml10"
|
||||
<el-button
|
||||
icon="Upload"
|
||||
type="success"
|
||||
class="ml10"
|
||||
@click="handleImport">
|
||||
导入
|
||||
</el-button>
|
||||
<el-button
|
||||
icon="Download"
|
||||
type="warning"
|
||||
class="ml10"
|
||||
<el-button
|
||||
icon="Download"
|
||||
type="warning"
|
||||
class="ml10"
|
||||
@click="handleExport">
|
||||
导出
|
||||
</el-button>
|
||||
@@ -204,10 +210,10 @@
|
||||
<form-dialog ref="formDialogRef" @refresh="getDataList" />
|
||||
|
||||
<!-- 导入对话框 -->
|
||||
<el-dialog
|
||||
title="导入数据"
|
||||
v-model="importDialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
<el-dialog
|
||||
title="导入数据"
|
||||
v-model="importDialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
width="500px">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
@@ -235,6 +241,47 @@
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 统计对话框 -->
|
||||
<el-dialog
|
||||
v-model="statisticsDialogVisible"
|
||||
title="团员统计"
|
||||
width="700px"
|
||||
destroy-on-close>
|
||||
<!-- 全校总数 -->
|
||||
<div class="statistics-total">
|
||||
<el-statistic title="全校团员总数" :value="statisticsData.totalCount || 0">
|
||||
<template #suffix>
|
||||
<span style="font-size: 14px; color: #909399;">人</span>
|
||||
</template>
|
||||
</el-statistic>
|
||||
</div>
|
||||
|
||||
<el-divider content-position="left">各学院团员统计</el-divider>
|
||||
|
||||
<!-- 各学院统计表格 -->
|
||||
<el-table
|
||||
:data="statisticsData.deptList || []"
|
||||
v-loading="statisticsLoading"
|
||||
stripe
|
||||
max-height="400px"
|
||||
:cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle">
|
||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||
<el-table-column prop="deptName" label="学院名称" align="center" min-width="150" />
|
||||
<el-table-column prop="count" label="团员人数" align="center" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag size="small" type="success" effect="plain" round>
|
||||
{{ row.count }} 人
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<template #footer>
|
||||
<el-button @click="statisticsDialogVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -242,13 +289,13 @@
|
||||
import { reactive, ref, onMounted, computed, nextTick } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import { fetchList, delObj, importExcel, exportExcel } from "/@/api/stuwork/stuunionleague";
|
||||
import { fetchList, delObj, importExcel, exportExcel, getStatistics } from "/@/api/stuwork/stuunionleague";
|
||||
import { getClassListByRole } from "/@/api/basic/basicclass";
|
||||
import { getGradeList } from "/@/api/basic/basicclass";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { parseTime } from "/@/utils/formatTime";
|
||||
import TableColumnControl from '/@/components/TableColumnControl/index.vue'
|
||||
import { UploadFilled, List, OfficeBuilding, Grid, CreditCard, Avatar, Phone, Calendar, Postcard, Briefcase, Setting, Menu, Search, Document } from '@element-plus/icons-vue'
|
||||
import { UploadFilled, List, OfficeBuilding, Grid, CreditCard, Avatar, Phone, Calendar, Postcard, Briefcase, Setting, Menu, Search, Document, DataAnalysis } from '@element-plus/icons-vue'
|
||||
import { useTableColumnControl } from '/@/hooks/tableColumn'
|
||||
|
||||
import type { UploadFile, UploadFiles } from 'element-plus';
|
||||
@@ -267,6 +314,14 @@ const importDialogVisible = ref(false)
|
||||
const importLoading = ref(false)
|
||||
const fileList = ref<UploadFile[]>([])
|
||||
|
||||
// 统计相关变量
|
||||
const statisticsDialogVisible = ref(false)
|
||||
const statisticsLoading = ref(false)
|
||||
const statisticsData = ref<any>({
|
||||
totalCount: 0,
|
||||
deptList: []
|
||||
})
|
||||
|
||||
// 表格列配置
|
||||
const tableColumns = [
|
||||
{ prop: 'deptName', label: '学院名称', minWidth: 150 },
|
||||
@@ -452,6 +507,22 @@ const getGradeListData = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 打开统计对话框
|
||||
const handleStatistics = async () => {
|
||||
statisticsDialogVisible.value = true
|
||||
statisticsLoading.value = true
|
||||
try {
|
||||
const res = await getStatistics()
|
||||
if (res.data) {
|
||||
statisticsData.value = res.data
|
||||
}
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg || '获取统计数据失败')
|
||||
} finally {
|
||||
statisticsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// ???
|
||||
onMounted(() => {
|
||||
getClassListData()
|
||||
|
||||
Reference in New Issue
Block a user