This commit is contained in:
2026-08-17 11:01:48 +08:00
parent e4485d7b02
commit ac5a2d902e
54 changed files with 2108 additions and 379 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ nutz:
ignore: ^(.+[.])(jsp|png|gif|jpg|js|css|jspx|jpeg|html|mp3|mp4|ico|svg|vue)$
exclusions: /favicon/*,/assets/*,/druid/*,/upload/*,/components/*
server:
port: 80
port: 8080
host: 0.0.0.0
jetty:
@@ -0,0 +1,7 @@
-- 体育活动增加模板设置状态,并根据现有工作模板回填历史数据。
ALTER TABLE `activity_school`
ADD COLUMN `templateStatus` tinyint(1) NOT NULL DEFAULT 0 COMMENT '模板设置状态 0.未设置 1.已设置' AFTER `isSave`;
UPDATE `activity_school` school
INNER JOIN `sys_home_template` template ON template.`id` = school.`id`
SET school.`templateStatus` = 1;
@@ -0,0 +1,8 @@
-- 文化活动增加模板设置状态,并只回填校工会文化活动的历史模板数据。
ALTER TABLE `activity_tissue`
ADD COLUMN `templateStatus` tinyint(1) NOT NULL DEFAULT 0 COMMENT '模板设置状态 0.未设置 1.已设置';
UPDATE `activity_tissue` tissue
INNER JOIN `sys_home_template` template ON template.`id` = tissue.`id`
SET tissue.`templateStatus` = 1
WHERE tissue.`activity_type` = 40001;
@@ -0,0 +1,5 @@
-- 使用现有模板设置状态字段,回填分工会文化活动的历史模板数据。
UPDATE `activity_tissue` tissue
INNER JOIN `sys_home_template` template ON template.`id` = tissue.`id`
SET tissue.`templateStatus` = 1
WHERE tissue.`activity_type` = 40002;
@@ -0,0 +1,7 @@
-- 作品征集活动增加模板设置状态,并根据现有工作模板回填历史数据。
ALTER TABLE `activity_works_collection`
ADD COLUMN `templateStatus` tinyint(1) NOT NULL DEFAULT 0 COMMENT '模板设置状态 0.未设置 1.已设置';
UPDATE `activity_works_collection` activity
INNER JOIN `sys_home_template` template ON template.`id` = activity.`id`
SET activity.`templateStatus` = 1;
@@ -0,0 +1,7 @@
-- 亲子活动增加模板设置状态,并根据现有工作模板回填历史数据。
ALTER TABLE `family_activity`
ADD COLUMN `templateStatus` tinyint(1) NOT NULL DEFAULT 0 COMMENT '模板设置状态 0.未设置 1.已设置';
UPDATE `family_activity` activity
INNER JOIN `sys_home_template` template ON template.`id` = activity.`id`
SET activity.`templateStatus` = 1;
@@ -0,0 +1,64 @@
-- 待确认人员记录菜单。以“变更记录”为同级菜单,并复制原变更记录菜单的角色授权。
INSERT INTO sys_menu (
id, parentId, path, name, aliasName, type, href, target, icon, showit, disabled,
permission, note, location, hasChildren, createdBy, createdAt, updatedBy, updatedAt,
delFlag, platform, moduleId, picIcon, initialPinyinName, isRecommendApp, isRecommendService
)
SELECT
'76a21e7d35df4ffbaecce44b3a659901',
source_menu.parentId,
CONCAT(
LEFT(source_menu.path, CHAR_LENGTH(source_menu.path) - 4),
LPAD(
IFNULL((
SELECT MAX(CAST(RIGHT(child.path, 4) AS UNSIGNED))
FROM sys_menu child
WHERE child.parentId = source_menu.parentId
), 0) + 1,
4,
'0'
)
),
'待确认人员记录',
'Pending Personnel',
'menu',
'/platform/sourcechange/pending',
'data-pjax',
'',
1,
0,
'staff.sourcechange.pending',
'全量人员数据差异待人工确认记录',
source_menu.location + 1,
0,
'',
UNIX_TIMESTAMP(NOW()) * 1000,
'',
UNIX_TIMESTAMP(NOW()) * 1000,
0,
'PC',
source_menu.moduleId,
NULL,
'd',
0,
0
FROM sys_menu source_menu
WHERE source_menu.permission = 'staff.sourcechange.manage'
AND NOT EXISTS (
SELECT 1
FROM (SELECT id FROM sys_menu WHERE permission = 'staff.sourcechange.pending') existing_menu
);
-- 原先能够查看“变更记录”的角色默认拥有“待确认人员记录”权限,避免新页面上线后无人可见。
INSERT INTO sys_role_menu (roleId, menuId)
SELECT source_role.roleId, pending_menu.id
FROM sys_role_menu source_role
JOIN sys_menu source_menu
ON source_menu.id = source_role.menuId
AND source_menu.permission = 'staff.sourcechange.manage'
JOIN sys_menu pending_menu
ON pending_menu.permission = 'staff.sourcechange.pending'
LEFT JOIN sys_role_menu existing_role
ON existing_role.roleId = source_role.roleId
AND existing_role.menuId = pending_menu.id
WHERE existing_role.roleId IS NULL;
@@ -0,0 +1,8 @@
-- 已初始化环境通过权限标识定位菜单,仅更新展示信息,不改变权限和访问路径。
UPDATE sys_menu
SET name = '服务单位管理',
aliasName = 'Service Unit',
initialPinyinName = 'f',
updatedAt = UNIX_TIMESTAMP(NOW()) * 1000
WHERE permission = 'tour.travelAgency'
AND delFlag = 0;
@@ -0,0 +1,18 @@
-- 待确认人员人工确认备注字段。已有字段的环境重复执行不会改变表结构。
SET @pending_remark_column_count = (
SELECT COUNT(*)
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'sys_user_history'
AND COLUMN_NAME = 'remark'
);
SET @pending_remark_ddl = IF(
@pending_remark_column_count = 0,
'ALTER TABLE sys_user_history ADD COLUMN remark TEXT NULL COMMENT ''备注'' AFTER changeReason',
'SELECT 1'
);
PREPARE pending_remark_stmt FROM @pending_remark_ddl;
EXECUTE pending_remark_stmt;
DEALLOCATE PREPARE pending_remark_stmt;
@@ -0,0 +1,3 @@
-- 省内参加间隔按工号、年度、线路类型和参加状态查询,补充联合索引降低报名校验耗时。
ALTER TABLE `tour_ledger`
ADD KEY `idx_tour_ledger_in_province_check` (`jobNo`, `joined`, `delFlag`, `lineType`, `year`);
@@ -0,0 +1,3 @@
-- 分工会名额校验按事项、分工会和删除状态统计报名人数,补充联合索引降低抢票时锁内查询耗时。
ALTER TABLE `tour_ledger`
ADD KEY `idx_tour_ledger_matter_union_del` (`matterId`, `unionId`, `delFlag`);
@@ -0,0 +1,3 @@
-- 疗休养配置增加省内参加间隔年限,历史配置默认不限制。
ALTER TABLE `tour_setting`
ADD COLUMN `inProvinceYears` int DEFAULT 0 COMMENT '省内几年去一次' AFTER `maxGroupPeople`;
@@ -0,0 +1,7 @@
-- 品牌活动增加模板设置状态,并根据现有工作模板回填历史数据。
ALTER TABLE `train_sign_up_activity`
ADD COLUMN `templateStatus` tinyint(1) NOT NULL DEFAULT 0 COMMENT '模板设置状态 0.未设置 1.已设置';
UPDATE `train_sign_up_activity` activity
INNER JOIN `sys_home_template` template ON template.`id` = activity.`id`
SET activity.`templateStatus` = 1;
@@ -681,6 +681,7 @@ const ACTIVITY_CULTURE_APPLY_ACTIVITY = {
data.taskId = null
data.startTaskId = null
data.isTemplate = false
data.templateStatus = 0
data.createdBy = null
data.createdAt = null
data.updatedBy = null
@@ -5,7 +5,8 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
template: /*language=HTML*/`
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="culture-info-manage-layout">
<el-card class="culture-info-query-card" shadow="never">
<search @search="doSearch">
<search-item label="活动时间">
@@ -26,12 +27,17 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="活动列表">
<el-card class="mt10 culture-info-list-card" shadow="never">
<el-tabs v-if="canManageTemplate" v-model="activeTab" @tab-click="tabChange">
<el-tab-pane label="活动列表" name="activity"></el-tab-pane>
<el-tab-pane label="活动模板列表" name="template"></el-tab-pane>
</el-tabs>
<table-tool :label="canManageTemplate && activeTab === 'template' ? '活动模板列表' : '活动列表'">
</table-tool>
<el-table :data="tableData" :size="tableSize" @sort-change="pageOrder"
class="vi-table" row-key="id" style="width: 100%;margin-bottom: 20px"
<el-table :data="tableData" :height="isTemplateManagedActivity ? tableHeight : null" :size="tableSize" @sort-change="pageOrder"
class="vi-table" ref="activityTableRef" row-key="id"
:style="{width: '100%', marginBottom: isTemplateManagedActivity ? '0' : '20px'}"
v-loading="tableLoading">
<el-table-column :index="indexMethod" align="center" header-align="center"
@@ -113,12 +119,12 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
</el-dropdown-item>
<el-dropdown-item
v-if="activity_type === 40001 && $auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && !row.isTemplate"
v-if="canManageTemplate && !row.isTemplate"
:command="{type:'setTemplate',row}">
设为模板
</el-dropdown-item>
<el-dropdown-item
v-if="activity_type === 40001 && $auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && row.isTemplate"
v-if="canManageTemplate && row.isTemplate"
:command="{type:'cancelTemplate',row}">
取消模板
</el-dropdown-item>
@@ -139,6 +145,7 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit>
@@ -162,6 +169,7 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
<el-button @click="codeDialogVisible = false" type="primary">关 闭</el-button>
</span>
</el-dialog>
<slot></slot>
</guava>
`,
props: {
@@ -172,6 +180,9 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
mixins: [initTableMixins],
data() {
return {
activeTab: "activity",
tableHeight: 300,
tableResizeObserver: null,
codeDialogVisible: false,
pageForm: {
year: new Date().getFullYear() + ""
@@ -188,23 +199,33 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
url: ""
}
},
computed: {
// 当前双页签及满高列表仅用于校工会、分工会文化活动,社团页面保持原样。
isTemplateManagedActivity() {
return this.activity_type === 40001 || this.activity_type === 40002
},
// 文化活动页签沿用“设为模板”按钮的角色范围,不新增权限标识。
canManageTemplate() {
return this.isTemplateManagedActivity && this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
}
},
components: {
"activity-culture-apply-activity": ACTIVITY_CULTURE_APPLY_ACTIVITY,
"activity-culture-info-activity": ACTIVITY_CULTURE_INFO_ACTIVITY
},
methods: {
async activityStatusChange(id, isUnseal) {
const resp = await this.$axios.post("/platform/activity/culture/infoManage/activityStatusChange", {
activityStatusChange(id, isUnseal) {
this.$axios.post("/platform/activity/culture/infoManage/activityStatusChange", {
id: id,
isUnseal: isUnseal
}).then((resp) => {
if (resp.code === 0) {
this.doSearch()
this.$message.success(resp.msg)
} else {
this.$message.error(resp.msg)
}
})
if (resp.code === 0) {
this.doSearch()
this.$message.success(resp.msg)
} else {
this.$message.error(resp.msg)
}
},
isUnsealDisabled(row) {
// 流程类活动只有在流程结束后才允许开启或关闭,非流程类活动保持原有开关逻辑。
@@ -231,6 +252,52 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
commonUtil.pjaxPush("/platform/activity/info/mange/export?id=" + row.id)
}
},
// 切换页签时按活动表中的模板状态重新查询,并重置分页位置。
tabChange() {
this.$set(this.pageForm, "templateStatus", this.activeTab === "template" ? 1 : 0)
this.doSearch()
this.updateTableHeight()
},
// 根据列表卡片可用空间固定表格高度,使大量数据只在表格内部滚动。
updateTableHeight() {
if (!this.isTemplateManagedActivity) {
return
}
this.$nextTick(() => {
const cardBody = this.$el.querySelector(".culture-info-list-card > .el-card__body")
if (!cardBody || cardBody.clientHeight <= 0) {
return
}
const getOuterHeight = (element) => {
if (!element) {
return 0
}
const style = window.getComputedStyle(element)
return element.offsetHeight
+ (parseFloat(style.marginTop) || 0)
+ (parseFloat(style.marginBottom) || 0)
}
const bodyStyle = window.getComputedStyle(cardBody)
const bodyPadding = (parseFloat(bodyStyle.paddingTop) || 0)
+ (parseFloat(bodyStyle.paddingBottom) || 0)
const tabs = this.canManageTemplate ? cardBody.querySelector(".el-tabs") : null
const tableTool = cardBody.querySelector(".ele-table-tool")
const pagination = cardBody.querySelector(".el-pagination-container")
const reservedHeight = bodyPadding
+ getOuterHeight(tabs)
+ getOuterHeight(tableTool)
+ getOuterHeight(pagination)
const nextHeight = Math.max(1, Math.floor(cardBody.clientHeight - reservedHeight))
if (this.tableHeight !== nextHeight) {
this.tableHeight = nextHeight
}
this.$nextTick(() => {
if (this.$refs.activityTableRef) {
this.$refs.activityTableRef.doLayout()
}
})
})
},
goBack() {
this.doSearch()
this.$refs.guava.index()
@@ -251,16 +318,17 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
return
}
const {id} = row
this.$confirm("确定要删除该活动吗?", "提示", {type: "warning"}).then(async () => {
this.$confirm("确定要删除该活动吗?", "提示", {type: "warning"}).then(() => {
this.$set(row, "loading", true)
const resp = await this.$axios.post("/platform/activity/culture/infoManage/doDelete", {id: id})
if (resp.code === 0) {
this.doSearch()
this.$message.success(resp.msg)
} else {
this.$message.error(resp.msg)
}
this.$set(row, "loading", false)
this.$axios.post("/platform/activity/culture/infoManage/doDelete", {id: id}).then((resp) => {
if (resp.code === 0) {
this.doSearch()
this.$message.success(resp.msg)
} else {
this.$message.error(resp.msg)
}
this.$set(row, "loading", false)
})
})
},
setTemplate(row) {
@@ -268,16 +336,17 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
}).then(() => {
this.$set(row, "loading", true)
const resp = await this.$axios.post("/platform/activity/culture/infoManage/setTemplate", {id: row.id})
if (resp.code === 0) {
this.doSearch()
this.$message.success(resp.msg)
} else {
this.$message.error(resp.msg)
}
this.$set(row, "loading", false)
this.$axios.post("/platform/activity/culture/infoManage/setTemplate", {id: row.id}).then((resp) => {
if (resp.code === 0) {
this.doSearch()
this.$message.success(resp.msg)
} else {
this.$message.error(resp.msg)
}
this.$set(row, "loading", false)
})
})
},
cancelTemplate(row) {
@@ -285,16 +354,17 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
}).then(() => {
this.$set(row, "loading", true)
const resp = await this.$axios.post("/platform/activity/culture/infoManage/cancelTemplate", {id: row.id})
if (resp.code === 0) {
this.doSearch()
this.$message.success(resp.msg)
} else {
this.$message.error(resp.msg)
}
this.$set(row, "loading", false)
this.$axios.post("/platform/activity/culture/infoManage/cancelTemplate", {id: row.id}).then((resp) => {
if (resp.code === 0) {
this.doSearch()
this.$message.success(resp.msg)
} else {
this.$message.error(resp.msg)
}
this.$set(row, "loading", false)
})
})
},
onRevoke(row) {
@@ -319,12 +389,12 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
this.tableData = res.data.list
this.pageForm.totalCount = res.data.totalCount
}
this.tableLoading = false
})
this.tableLoading = false
},
},
async created() {
created() {
// 根据 activity_type 动态添加流程相关列
if (this.activity_type === 40002 || this.activity_type === 40003) {
this.tableColumns.push(
@@ -332,6 +402,30 @@ const ACTIVITY_CULTURE_INFO_MANAGE = {
{prop: "instanceState", label: "流程状态"}
);
}
if (this.canManageTemplate) {
// 有模板管理角色时默认进入活动列表,只展示未设置模板的校工会活动。
this.$set(this.pageForm, "templateStatus", 0)
}
this.pageData()
},
mounted() {
if (!this.isTemplateManagedActivity) {
return
}
const listCardBody = this.$el.querySelector(".culture-info-list-card > .el-card__body")
if (listCardBody && window.ResizeObserver) {
// 查询区换行、页签权限或窗口变化时同步调整表格内部滚动区域。
this.tableResizeObserver = new ResizeObserver(this.updateTableHeight)
this.tableResizeObserver.observe(listCardBody)
}
this.updateTableHeight()
window.addEventListener("resize", this.updateTableHeight)
},
beforeDestroy() {
if (this.tableResizeObserver) {
this.tableResizeObserver.disconnect()
this.tableResizeObserver = null
}
window.removeEventListener("resize", this.updateTableHeight)
}
}
@@ -2,6 +2,39 @@
layout("/layouts/platform.html"){
#-->
<style>
/* 校工会文化活动列表占满平台内容区,页面本身不产生纵向滚动条。 */
#app .culture-info-manage-layout {
display: flex;
flex-direction: column;
min-height: 0;
height: calc(100vh - 82px);
overflow: hidden;
}
#app .culture-info-query-card {
flex: 0 0 auto;
}
/* 列表卡片填充剩余高度,表格高度由组件根据固定区域动态计算。 */
#app .culture-info-list-card {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#app .culture-info-list-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
overflow: hidden;
}
#app .culture-info-list-card .el-tabs,
#app .culture-info-list-card .ele-table-tool,
#app .culture-info-list-card .el-pagination-container {
flex: 0 0 auto;
}
</style>
<div id="app" v-cloak>
<activity-culture-info-manage :activity_type="activityType"></activity-culture-info-manage>
</div>
@@ -2,6 +2,39 @@
layout("/layouts/platform.html"){
#-->
<style>
/* 分工会文化活动列表占满平台内容区,页面本身不产生纵向滚动条。 */
#app .culture-info-manage-layout {
display: flex;
flex-direction: column;
min-height: 0;
height: calc(100vh - 82px);
overflow: hidden;
}
#app .culture-info-query-card {
flex: 0 0 auto;
}
/* 列表卡片填充剩余高度,表格高度由组件根据固定区域动态计算。 */
#app .culture-info-list-card {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#app .culture-info-list-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
overflow: hidden;
}
#app .culture-info-list-card .el-tabs,
#app .culture-info-list-card .ele-table-tool,
#app .culture-info-list-card .el-pagination-container {
flex: 0 0 auto;
}
</style>
<div id="app" v-cloak>
<activity-culture-info-manage :activity_type="activityType"></activity-culture-info-manage>
</div>
@@ -514,6 +514,7 @@ const basicForm = {
}
data.id = null
data.isTemplate = false
data.templateStatus = 0
data.createdBy = null
data.createdAt = null
data.updatedBy = null
@@ -15,12 +15,43 @@ layout("/layouts/platform.html"){
.el-row--flex {
align-items: center;
}
/* 亲子活动管理占满平台内容区,页面本身不产生纵向滚动条。 */
#app .family-activity-manage-layout {
display: flex;
flex-direction: column;
min-height: 0;
height: calc(100vh - 82px);
overflow: hidden;
}
#app .family-activity-query-card {
flex: 0 0 auto;
}
/* 列表卡片填充剩余高度,超出数据仅在表格内部滚动。 */
#app .family-activity-list-card {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#app .family-activity-list-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
overflow: hidden;
}
#app .family-activity-list-card .el-tabs,
#app .family-activity-list-card .ele-table-tool,
#app .family-activity-list-card .el-pagination-container {
flex: 0 0 auto;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<template>
<div class="family-activity-manage-layout">
<el-card class="family-activity-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -44,13 +75,21 @@ layout("/layouts/platform.html"){
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="活动列表">
<el-button @click="openAdd" size="small" type="primary">
<el-card class="mt10 family-activity-list-card" shadow="never">
<el-tabs v-if="canManageTemplate" v-model="activeTab" @tab-click="tabChange">
<el-tab-pane label="活动列表" name="activity"></el-tab-pane>
<el-tab-pane label="活动模板列表" name="template"></el-tab-pane>
</el-tabs>
<table-tool :label="canManageTemplate && activeTab === 'template' ? '活动模板列表' : '活动列表'">
<el-button
@click="openAdd"
size="small"
type="primary"
v-if="!canManageTemplate || activeTab === 'activity'">
<i class="ti-plus"></i>新建活动
</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table :data="tableData" :height="tableHeight" :size="tableSize" ref="activityTableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column
:label="column.label"
@@ -93,12 +132,12 @@ layout("/layouts/platform.html"){
<el-dropdown-item @click.native="onView(row)">查看</el-dropdown-item>
<el-dropdown-item @click.native="openEdit(row)">编辑</el-dropdown-item>
<el-dropdown-item
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && !row.isTemplate"
v-if="canManageTemplate && row.templateStatus !== 1"
@click.native="setTemplate(row)">设为模板</el-dropdown-item>
<el-dropdown-item
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && row.isTemplate"
v-if="canManageTemplate && row.templateStatus === 1"
@click.native="cancelTemplate(row)">取消模板</el-dropdown-item>
<el-dropdown-item :disabled="!!row.isTemplate" @click.native="onDelete(row)">删除</el-dropdown-item>
<el-dropdown-item :disabled="row.templateStatus === 1" @click.native="onDelete(row)">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
@@ -106,6 +145,8 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit>
<basic-form ref="formRef" @back="back" @refresh="doSearch"></basic-form>
@@ -148,6 +189,9 @@ layout("/layouts/platform.html"){
},
data() {
return {
activeTab: "activity",
tableHeight: 300,
tableResizeObserver: null,
pageForm: {
year: new Date().getFullYear() + ''
},
@@ -161,7 +205,56 @@ layout("/layouts/platform.html"){
activityUrl: '',
}
},
computed: {
// 页签沿用“设为模板”按钮的角色范围,不新增权限标识。
canManageTemplate() {
return this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
}
},
methods: {
// 切换页签时按亲子活动表中的模板状态查询,并重置分页位置。
tabChange() {
this.$set(this.pageForm, "templateStatus", this.activeTab === "template" ? 1 : 0)
this.doSearch()
this.updateTableHeight()
},
// 根据列表卡片可用空间固定表格高度,使大量数据只在表格内部滚动。
updateTableHeight() {
this.$nextTick(() => {
const cardBody = this.$el.querySelector(".family-activity-list-card > .el-card__body")
if (!cardBody || cardBody.clientHeight <= 0) {
return
}
const getOuterHeight = (element) => {
if (!element) {
return 0
}
const style = window.getComputedStyle(element)
return element.offsetHeight
+ (parseFloat(style.marginTop) || 0)
+ (parseFloat(style.marginBottom) || 0)
}
const bodyStyle = window.getComputedStyle(cardBody)
const bodyPadding = (parseFloat(bodyStyle.paddingTop) || 0)
+ (parseFloat(bodyStyle.paddingBottom) || 0)
const tabs = this.canManageTemplate ? cardBody.querySelector(".el-tabs") : null
const tableTool = cardBody.querySelector(".ele-table-tool")
const pagination = cardBody.querySelector(".el-pagination-container")
const reservedHeight = bodyPadding
+ getOuterHeight(tabs)
+ getOuterHeight(tableTool)
+ getOuterHeight(pagination)
const nextHeight = Math.max(1, Math.floor(cardBody.clientHeight - reservedHeight))
if (this.tableHeight !== nextHeight) {
this.tableHeight = nextHeight
}
this.$nextTick(() => {
if (this.$refs.activityTableRef) {
this.$refs.activityTableRef.doLayout()
}
})
})
},
back() {
this.$refs.guava.index()
},
@@ -187,16 +280,17 @@ layout("/layouts/platform.html"){
makeCode(row) {
this.$refs.codeRef.initData(row)
},
async activityStatusChange(notice, val, id) {
const resp = await this.$axios.post(loc() + "/activityStatusChange", { notice: notice, isDisabled: val, id })
if (resp.code === 0) {
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
activityStatusChange(notice, val, id) {
this.$axios.post(loc() + "/activityStatusChange", { notice: notice, isDisabled: val, id: id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
})
},
async onDelete(row) {
if (row.isTemplate) {
onDelete(row) {
if (row.templateStatus === 1) {
this.$message.warning("该活动已设为模板,请先取消模板后再删除")
return
}
@@ -204,49 +298,73 @@ layout("/layouts/platform.html"){
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post(loc() + "/onDelete", { id: row.id })
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
}).then(() => {
this.$axios.post(loc() + "/onDelete", { id: row.id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
})
}).catch(() => {})
},
async setTemplate(row) {
setTemplate(row) {
this.$confirm("确定将该活动设为工作模板吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post(loc() + "/setTemplate", { id: row.id })
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
}).then(() => {
this.$axios.post(loc() + "/setTemplate", { id: row.id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
})
}).catch(() => {})
},
async cancelTemplate(row) {
cancelTemplate(row) {
this.$confirm("确定取消该活动的工作模板吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post(loc() + "/cancelTemplate", { id: row.id })
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
}).then(() => {
this.$axios.post(loc() + "/cancelTemplate", { id: row.id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
})
}).catch(() => {})
},
},
async created() {
created() {
if (this.canManageTemplate) {
// 有模板管理角色时默认进入活动列表,只展示未设置模板的活动。
this.$set(this.pageForm, "templateStatus", 0)
}
this.pageData()
},
mounted() {
const listCardBody = this.$el.querySelector(".family-activity-list-card > .el-card__body")
if (listCardBody && window.ResizeObserver) {
// 查询区换行、页签权限或窗口变化时同步调整表格内部滚动区域。
this.tableResizeObserver = new ResizeObserver(this.updateTableHeight)
this.tableResizeObserver.observe(listCardBody)
}
this.updateTableHeight()
window.addEventListener("resize", this.updateTableHeight)
},
beforeDestroy() {
if (this.tableResizeObserver) {
this.tableResizeObserver.disconnect()
this.tableResizeObserver = null
}
window.removeEventListener("resize", this.updateTableHeight)
}
})
</script>
@@ -5,36 +5,50 @@ layout("/layouts/platform.html"){
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="请选择年度"
style="width: 100%"
type="year"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<div class="sports-info-manage-layout">
<el-card class="sports-info-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
placeholder="请选择年度"
style="width: 100%"
type="year"
v-model="pageForm.year"
value-format="yyyy"
></el-date-picker>
</search-item>
<search-item label="活动名称">
<el-input clearable placeholder="请输入活动名称" v-model="pageForm.name"></el-input>
</search-item>
</search>
</el-card>
<search-item label="活动名称">
<el-input clearable placeholder="请输入活动名称" v-model="pageForm.name"></el-input>
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="活动列表">
<el-button @click="openAdd" icon="el-icon-edit-outline" size="small" type="primary">创建活动</el-button>
<el-card class="mt10 sports-info-list-card" shadow="never">
<el-tabs v-if="canManageTemplate" v-model="activeTab" @tab-click="tabChange">
<el-tab-pane label="活动列表" name="activity"></el-tab-pane>
<el-tab-pane label="活动模板列表" name="template"></el-tab-pane>
</el-tabs>
<table-tool :label="canManageTemplate && activeTab === 'template' ? '活动模板列表' : '活动列表'">
<el-button
@click="openAdd"
icon="el-icon-edit-outline"
size="small"
type="primary"
v-if="!canManageTemplate || activeTab === 'activity'"
>创建活动</el-button>
</table-tool>
<el-table
:height="tableHeight"
:data="tableData"
:size="tableSize"
@sort-change="pageOrder"
class="vi-table"
ref="activityTableRef"
row-key="id"
style="width: 100%; margin-bottom: 20px"
style="width: 100%"
>
<el-table-column
:index="indexMethod"
@@ -100,8 +114,9 @@ layout("/layouts/platform.html"){
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit_func>
@@ -126,6 +141,43 @@ layout("/layouts/platform.html"){
</guava>
</div>
<style>
/* 活动列表页占满平台内容区,页面本身不产生纵向滚动条。 */
#app .sports-info-manage-layout {
display: flex;
flex-direction: column;
min-height: 0;
height: calc(100vh - 82px);
overflow: hidden;
}
#app .sports-info-query-card {
flex: 0 0 auto;
}
/* 列表卡片填充剩余高度,表格高度由脚本根据内部固定区域动态计算。 */
#app .sports-info-list-card {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#app .sports-info-list-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
overflow: hidden;
}
#app .sports-info-list-card .el-tabs,
#app .sports-info-list-card .ele-table-tool,
#app .sports-info-list-card .el-pagination-container {
flex: 0 0 auto;
}
</style>
<script nonce="${cspNonce!}">
<!--#include("info.js"){}#-->
@@ -137,6 +189,9 @@ layout("/layouts/platform.html"){
data() {
return {
user: null,
activeTab: "activity",
tableHeight: 300,
tableResizeObserver: null,
pageForm: {
year: this.$moment().format("YYYY") + ""
},
@@ -153,6 +208,12 @@ layout("/layouts/platform.html"){
]
}
},
computed: {
// 页签沿用“设为模板”按钮的角色范围,不新增权限标识。
canManageTemplate() {
return this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
}
},
components: {
"info-manage-info": ACTIVITY_SPORTS_INFO,
"add-activity": ACTIVITY_SPORTS_ADD_ACTIVITY
@@ -174,6 +235,49 @@ layout("/layouts/platform.html"){
window.open("/platform/activity/sports/info/mange/exportXlsx?id=" + row.id)
}
},
// 切换页签时按活动表中的模板设置状态重新查询,并重置分页位置。
tabChange() {
this.$set(this.pageForm, "templateStatus", this.activeTab === "template" ? 1 : 0)
this.doSearch()
this.updateTableHeight()
},
// 根据列表卡片的实际可用空间设置 Element Table 高度,使数据只在表格内部滚动。
updateTableHeight() {
this.$nextTick(() => {
const cardBody = this.$el.querySelector(".sports-info-list-card > .el-card__body")
if (!cardBody || cardBody.clientHeight <= 0) {
return
}
const getOuterHeight = (element) => {
if (!element) {
return 0
}
const style = window.getComputedStyle(element)
return element.offsetHeight
+ (parseFloat(style.marginTop) || 0)
+ (parseFloat(style.marginBottom) || 0)
}
const bodyStyle = window.getComputedStyle(cardBody)
const bodyPadding = (parseFloat(bodyStyle.paddingTop) || 0)
+ (parseFloat(bodyStyle.paddingBottom) || 0)
const tabs = this.canManageTemplate ? cardBody.querySelector(".el-tabs") : null
const tableTool = cardBody.querySelector(".ele-table-tool")
const pagination = cardBody.querySelector(".el-pagination-container")
const reservedHeight = bodyPadding
+ getOuterHeight(tabs)
+ getOuterHeight(tableTool)
+ getOuterHeight(pagination)
const nextHeight = Math.max(1, Math.floor(cardBody.clientHeight - reservedHeight))
if (this.tableHeight !== nextHeight) {
this.tableHeight = nextHeight
}
this.$nextTick(() => {
if (this.$refs.activityTableRef) {
this.$refs.activityTableRef.doLayout()
}
})
})
},
openView(row) {
const { id } = row
this.$refs.guava.view(() => {
@@ -275,7 +379,28 @@ layout("/layouts/platform.html"){
},
async created() {
this.user = this.$store.state.user
if (this.canManageTemplate) {
// 有模板管理角色时默认进入活动列表,只展示未设置模板的活动。
this.$set(this.pageForm, "templateStatus", 0)
}
this.pageData()
},
mounted() {
const listCardBody = this.$el.querySelector(".sports-info-list-card > .el-card__body")
if (listCardBody && window.ResizeObserver) {
// 查询区换行、页签权限或窗口尺寸变化时同步调整表格内部滚动区域。
this.tableResizeObserver = new ResizeObserver(this.updateTableHeight)
this.tableResizeObserver.observe(listCardBody)
}
this.updateTableHeight()
window.addEventListener("resize", this.updateTableHeight)
},
beforeDestroy() {
if (this.tableResizeObserver) {
this.tableResizeObserver.disconnect()
this.tableResizeObserver = null
}
window.removeEventListener("resize", this.updateTableHeight)
}
})
</script>
@@ -15,12 +15,43 @@ layout("/layouts/platform.html"){
.courseTimeButton {
padding: 0 !important;
}
/* 品牌活动管理占满平台内容区,页面本身不产生纵向滚动条。 */
#app .train-sign-up-manage-layout {
display: flex;
flex-direction: column;
min-height: 0;
height: calc(100vh - 82px);
overflow: hidden;
}
#app .train-sign-up-query-card {
flex: 0 0 auto;
}
/* 列表卡片填充剩余高度,超出数据仅在表格内部滚动。 */
#app .train-sign-up-list-card {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#app .train-sign-up-list-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
overflow: hidden;
}
#app .train-sign-up-list-card .el-tabs,
#app .train-sign-up-list-card .ele-table-tool,
#app .train-sign-up-list-card .el-pagination-container {
flex: 0 0 auto;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<el-card shadow="never">
<template>
<div class="train-sign-up-manage-layout">
<el-card class="train-sign-up-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker
@@ -44,13 +75,21 @@ layout("/layouts/platform.html"){
</search-item>
</search>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="活动列表">
<el-button @click="openAdd" size="small" type="primary">
<el-card class="mt10 train-sign-up-list-card" shadow="never">
<el-tabs v-if="canManageTemplate" v-model="activeTab" @tab-click="tabChange">
<el-tab-pane label="活动列表" name="activity"></el-tab-pane>
<el-tab-pane label="活动模板列表" name="template"></el-tab-pane>
</el-tabs>
<table-tool :label="canManageTemplate && activeTab === 'template' ? '活动模板列表' : '活动列表'">
<el-button
@click="openAdd"
size="small"
type="primary"
v-if="!canManageTemplate || activeTab === 'activity'">
<i class="ti-plus"></i>新建活动
</el-button>
</table-tool>
<el-table :data="tableData" :size="tableSize">
<el-table :data="tableData" :height="tableHeight" :size="tableSize" ref="activityTableRef">
<el-table-column :index="indexMethod" label="序号" type="index" width="80px"></el-table-column>
<el-table-column
:label="column.label"
@@ -93,12 +132,12 @@ layout("/layouts/platform.html"){
<el-dropdown-item @click.native="onView(row)">查看</el-dropdown-item>
<el-dropdown-item @click.native="openEdit(row)">编辑</el-dropdown-item>
<el-dropdown-item
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && !row.isTemplate"
v-if="canManageTemplate && row.templateStatus !== 1"
@click.native="setTemplate(row)">设为模板</el-dropdown-item>
<el-dropdown-item
v-if="$auth.hasRoleOr(['SYSADMIN','SCHOOL_UNION_ADMIN']) && row.isTemplate"
v-if="canManageTemplate && row.templateStatus === 1"
@click.native="cancelTemplate(row)">取消模板</el-dropdown-item>
<el-dropdown-item :disabled="!!row.isTemplate" @click.native="onDelete(row)">删除</el-dropdown-item>
<el-dropdown-item :disabled="row.templateStatus === 1" @click.native="onDelete(row)">删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
@@ -106,6 +145,8 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit>
<basic-form ref="formRef" @back="back" @refresh="doSearch"></basic-form>
@@ -149,6 +190,9 @@ layout("/layouts/platform.html"){
},
data() {
return {
activeTab: "activity",
tableHeight: 300,
tableResizeObserver: null,
pageForm: {
year: new Date().getFullYear() + ''
},
@@ -163,6 +207,12 @@ layout("/layouts/platform.html"){
urlEditInitialized: false,
}
},
computed: {
// 页签沿用“设为模板”按钮的角色范围,不新增权限标识。
canManageTemplate() {
return this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
}
},
methods: {
pageData(data = null) {
const address = this.pageDataUrl ? this.pageDataUrl : loc() + "/pageData"
@@ -179,6 +229,49 @@ layout("/layouts/platform.html"){
return res
})
},
// 切换页签时按活动表中的模板状态查询,并重置到第一页。
tabChange() {
this.$set(this.pageForm, "templateStatus", this.activeTab === "template" ? 1 : 0)
this.doSearch()
this.updateTableHeight()
},
// 根据列表卡片的可用空间固定表格高度,使大量数据只在表格内部滚动。
updateTableHeight() {
this.$nextTick(() => {
const cardBody = this.$el.querySelector(".train-sign-up-list-card > .el-card__body")
if (!cardBody || cardBody.clientHeight <= 0) {
return
}
const getOuterHeight = (element) => {
if (!element) {
return 0
}
const style = window.getComputedStyle(element)
return element.offsetHeight
+ (parseFloat(style.marginTop) || 0)
+ (parseFloat(style.marginBottom) || 0)
}
const bodyStyle = window.getComputedStyle(cardBody)
const bodyPadding = (parseFloat(bodyStyle.paddingTop) || 0)
+ (parseFloat(bodyStyle.paddingBottom) || 0)
const tabs = this.canManageTemplate ? cardBody.querySelector(".el-tabs") : null
const tableTool = cardBody.querySelector(".ele-table-tool")
const pagination = cardBody.querySelector(".el-pagination-container")
const reservedHeight = bodyPadding
+ getOuterHeight(tabs)
+ getOuterHeight(tableTool)
+ getOuterHeight(pagination)
const nextHeight = Math.max(1, Math.floor(cardBody.clientHeight - reservedHeight))
if (this.tableHeight !== nextHeight) {
this.tableHeight = nextHeight
}
this.$nextTick(() => {
if (this.$refs.activityTableRef) {
this.$refs.activityTableRef.doLayout()
}
})
})
},
back() {
this.$refs.guava.index()
},
@@ -223,16 +316,17 @@ layout("/layouts/platform.html"){
makeCode(row) {
this.$refs.codeRef.initData(row)
},
async activityStatusChange(notice, val, id) {
const resp = await this.$axios.post(loc() + "/activityStatusChange", { notice: notice, isDisabled: val, id })
if (resp.code === 0) {
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
activityStatusChange(notice, val, id) {
this.$axios.post(loc() + "/activityStatusChange", { notice: notice, isDisabled: val, id: id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
} else {
this.$message.warning(resp.msg)
}
})
},
async onDelete(row) {
if (row.isTemplate) {
onDelete(row) {
if (row.templateStatus === 1) {
this.$message.warning("该活动已设为模板,请先取消模板后再删除")
return
}
@@ -240,49 +334,71 @@ layout("/layouts/platform.html"){
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post(loc() + "/onDelete", { id: row.id })
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
}).then(() => {
this.$axios.post(loc() + "/onDelete", { id: row.id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
})
}).catch(() => {})
},
async setTemplate(row) {
setTemplate(row) {
this.$confirm("确定将该活动设为工作模板吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post(loc() + "/setTemplate", { id: row.id })
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
}).then(() => {
this.$axios.post(loc() + "/setTemplate", { id: row.id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
})
}).catch(() => {})
},
async cancelTemplate(row) {
cancelTemplate(row) {
this.$confirm("确定取消该活动的工作模板吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(async () => {
const resp = await this.$axios.post(loc() + "/cancelTemplate", { id: row.id })
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
}).then(() => {
this.$axios.post(loc() + "/cancelTemplate", { id: row.id }).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.error(resp.msg)
}
})
}).catch(() => {})
},
},
mounted() {
if (this.canManageTemplate) {
// 有模板管理角色时默认进入活动列表,只展示未设置模板的活动。
this.$set(this.pageForm, "templateStatus", 0)
}
this.pageData()
const listCardBody = this.$el.querySelector(".train-sign-up-list-card > .el-card__body")
if (listCardBody && window.ResizeObserver) {
// 查询区换行、页签权限或窗口变化时同步调整表格内部滚动区域。
this.tableResizeObserver = new ResizeObserver(this.updateTableHeight)
this.tableResizeObserver.observe(listCardBody)
}
this.updateTableHeight()
window.addEventListener("resize", this.updateTableHeight)
},
beforeDestroy() {
if (this.tableResizeObserver) {
this.tableResizeObserver.disconnect()
this.tableResizeObserver = null
}
window.removeEventListener("resize", this.updateTableHeight)
}
})
</script>
@@ -2,12 +2,44 @@
layout("/layouts/platform.html"){
#-->
<style></style>
<style>
/* 作品征集活动管理占满平台内容区,页面本身不产生纵向滚动条。 */
#app .works-collection-manage-layout {
display: flex;
flex-direction: column;
min-height: 0;
height: calc(100vh - 82px);
overflow: hidden;
}
#app .works-collection-query-card {
flex: 0 0 auto;
}
/* 列表卡片填充剩余高度,超出数据仅在表格内部滚动。 */
#app .works-collection-list-card {
flex: 1 1 auto;
min-height: 0;
overflow: hidden;
}
#app .works-collection-list-card > .el-card__body {
box-sizing: border-box;
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
overflow: hidden;
}
#app .works-collection-list-card .el-tabs,
#app .works-collection-list-card .ele-table-tool,
#app .works-collection-list-card .el-pagination-container {
flex: 0 0 auto;
}
</style>
<div id="app" v-cloak>
<guava ref="guava">
<template>
<el-card shadow="never">
<div class="works-collection-manage-layout">
<el-card class="works-collection-query-card" shadow="never">
<search @search="doSearch">
<search-item label="年度">
<el-date-picker placeholder="请选择年度" type="year" v-model="pageForm.year"
@@ -19,12 +51,21 @@ layout("/layouts/platform.html"){
</search>
</el-card>
<el-card shadow="never">
<table-tool label="活动列表">
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openAdd">创建活动</el-button>
<el-card class="mt10 works-collection-list-card" shadow="never">
<el-tabs v-if="canManageTemplate" v-model="activeTab" @tab-click="tabChange">
<el-tab-pane label="活动列表" name="activity"></el-tab-pane>
<el-tab-pane label="活动模板列表" name="template"></el-tab-pane>
</el-tabs>
<table-tool :label="canManageTemplate && activeTab === 'template' ? '活动模板列表' : '活动列表'">
<el-button
size="mini"
type="primary"
icon="el-icon-plus"
@click="openAdd"
v-if="!canManageTemplate || activeTab === 'activity'">创建活动</el-button>
</table-tool>
<el-table :data="tableData" @sort-change="pageOrder" style="width: 100%" row-key="id">
<el-table :data="tableData" :height="tableHeight" @sort-change="pageOrder" ref="activityTableRef" style="width: 100%" row-key="id">
<el-table-column label="序号" type="index" width="60px" :index="indexMethod"></el-table-column>
<el-table-column label="主题" prop="name"></el-table-column>
<el-table-column label="创建人" prop="userName"></el-table-column>
@@ -74,6 +115,7 @@ layout("/layouts/platform.html"){
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
</div>
</template>
<template #edit>
@@ -361,6 +403,9 @@ layout("/layouts/platform.html"){
mixins: [initTableMixins],
data() {
return {
activeTab: "activity",
tableHeight: 300,
tableResizeObserver: null,
activityGroupList: [],
dialogFormVisible: false,
formRules: {
@@ -388,6 +433,12 @@ layout("/layouts/platform.html"){
clubOptions: [],
}
},
computed: {
// 页签沿用“设为模板”按钮的角色范围,不新增权限标识。
canManageTemplate() {
return this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
}
},
components: {
"drawer-user-scope": httpVueLoader("/components/module/activity/DrawerUserScope.vue")
},
@@ -426,9 +477,8 @@ layout("/layouts/platform.html"){
this.openAdd()
}
},
async getActivityGroup() {
const {data} = await this.$axios.post("/platform/activity/basic/scope/getActivityUserScopeGroup")
return data
getActivityGroup() {
return this.$axios.post("/platform/activity/basic/scope/getActivityUserScopeGroup").then((res) => res.data)
},
dropdownCommand(command) {
const {type, row} = command
@@ -444,6 +494,49 @@ layout("/layouts/platform.html"){
this.doDelete(row.id)
}
},
// 切换页签时按作品征集活动表中的模板状态查询,并重置分页位置。
tabChange() {
this.$set(this.pageForm, "templateStatus", this.activeTab === "template" ? 1 : 0)
this.doSearch()
this.updateTableHeight()
},
// 根据列表卡片可用空间固定表格高度,使大量数据只在表格内部滚动。
updateTableHeight() {
this.$nextTick(() => {
const cardBody = this.$el.querySelector(".works-collection-list-card > .el-card__body")
if (!cardBody || cardBody.clientHeight <= 0) {
return
}
const getOuterHeight = (element) => {
if (!element) {
return 0
}
const style = window.getComputedStyle(element)
return element.offsetHeight
+ (parseFloat(style.marginTop) || 0)
+ (parseFloat(style.marginBottom) || 0)
}
const bodyStyle = window.getComputedStyle(cardBody)
const bodyPadding = (parseFloat(bodyStyle.paddingTop) || 0)
+ (parseFloat(bodyStyle.paddingBottom) || 0)
const tabs = this.canManageTemplate ? cardBody.querySelector(".el-tabs") : null
const tableTool = cardBody.querySelector(".ele-table-tool")
const pagination = cardBody.querySelector(".el-pagination-container")
const reservedHeight = bodyPadding
+ getOuterHeight(tabs)
+ getOuterHeight(tableTool)
+ getOuterHeight(pagination)
const nextHeight = Math.max(1, Math.floor(cardBody.clientHeight - reservedHeight))
if (this.tableHeight !== nextHeight) {
this.tableHeight = nextHeight
}
this.$nextTick(() => {
if (this.$refs.activityTableRef) {
this.$refs.activityTableRef.doLayout()
}
})
})
},
async loadFormOptions() {
if (this.formOptionsLoaded) {
return
@@ -518,6 +611,7 @@ layout("/layouts/platform.html"){
}
data.id = null
data.isTemplate = false
data.templateStatus = 0
data.createdBy = null
data.createdAt = null
data.updatedBy = null
@@ -669,31 +763,29 @@ layout("/layouts/platform.html"){
})
})
},
async setTemplate(row) {
try {
await this.$confirm("确定将该活动设为工作模板吗?", "提示", {type: "warning"})
const resp = await this.$axios.post(loc() + "/setTemplate", {id: row.id})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
} catch (e) {
}
setTemplate(row) {
this.$confirm("确定将该活动设为工作模板吗?", "提示", {type: "warning"}).then(() => {
this.$axios.post(loc() + "/setTemplate", {id: row.id}).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
})
}).catch(() => {})
},
async cancelTemplate(row) {
try {
await this.$confirm("确定取消该工作模板吗?", "提示", {type: "warning"})
const resp = await this.$axios.post(loc() + "/cancelTemplate", {id: row.id})
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
} catch (e) {
}
cancelTemplate(row) {
this.$confirm("确定取消该工作模板吗?", "提示", {type: "warning"}).then(() => {
this.$axios.post(loc() + "/cancelTemplate", {id: row.id}).then((resp) => {
if (resp.code === 0) {
this.$message.success(resp.msg)
this.doSearch()
} else {
this.$message.warning(resp.msg)
}
})
}).catch(() => {})
},
enableChange(enable, id) {
@@ -727,12 +819,15 @@ layout("/layouts/platform.html"){
})
})
},
async getClubsByRole() {
const resp = await this.$axios.post("/platform/club/examine/apply/getClubsByRole")
return resp.data
getClubsByRole() {
return this.$axios.post("/platform/club/examine/apply/getClubsByRole").then((resp) => resp.data)
},
},
async created() {
if (!this.isNewPage() && this.canManageTemplate) {
// 有模板管理角色时默认进入活动列表,只展示未设置模板的活动。
this.$set(this.pageForm, "templateStatus", 0)
}
if (this.isNewPage()) {
await this.loadFormOptions()
this.$nextTick(() => {
@@ -742,6 +837,26 @@ layout("/layouts/platform.html"){
this.pageData()
this.loadFormOptions()
}
},
mounted() {
if (this.isNewPage()) {
return
}
const listCardBody = this.$el.querySelector(".works-collection-list-card > .el-card__body")
if (listCardBody && window.ResizeObserver) {
// 查询区换行、页签权限或窗口变化时同步调整表格内部滚动区域。
this.tableResizeObserver = new ResizeObserver(this.updateTableHeight)
this.tableResizeObserver.observe(listCardBody)
}
this.updateTableHeight()
window.addEventListener("resize", this.updateTableHeight)
},
beforeDestroy() {
if (this.tableResizeObserver) {
this.tableResizeObserver.disconnect()
this.tableResizeObserver = null
}
window.removeEventListener("resize", this.updateTableHeight)
}
})
</script>
@@ -8,16 +8,16 @@ const MEMBER_ALL_CHANGE_INFO = {
<el-descriptions-item label="性别">{{ viewData.sex }}</el-descriptions-item>
<el-descriptions-item label="民族">{{ viewData.nation }}</el-descriptions-item>
<el-descriptions-item label="出生日期">{{ $moment(viewData.birthday).format("YYYY年MM月DD日") }}</el-descriptions-item>
<el-descriptions-item label="出生日期">{{ viewData.birthday ? $moment(viewData.birthday).format("YYYY年MM月DD日") : "" }}</el-descriptions-item>
<el-descriptions-item label="政治面貌">{{ viewData.political }}</el-descriptions-item>
<el-descriptions-item label="学历">{{ viewData.education }}</el-descriptions-item>
<el-descriptions-item label="学位">{{ viewData.academicDegree }}</el-descriptions-item>
<el-descriptions-item label="党政职务">{{ viewData.position }}</el-descriptions-item>
<el-descriptions-item label="工作单位">{{ viewData.unitname }}</el-descriptions-item>
<el-descriptions-item label="所属工会">{{ viewData.unionname }}</el-descriptions-item>
<el-descriptions-item label="所属校区">{{ viewData.campus }}</el-descriptions-item>
<el-descriptions-item label="工作单位">{{ viewData.unitName }}</el-descriptions-item>
<el-descriptions-item label="所属工会">{{ viewData.unionName }}</el-descriptions-item>
<el-descriptions-item label="所属校区">{{ viewData.campusName }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ viewData.idCard }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ viewData.mobile }}</el-descriptions-item>
@@ -0,0 +1,232 @@
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="姓名/工号">
<el-input v-model="pageForm.searchKeyword" clearable placeholder="请输入姓名或工号"></el-input>
</search-item>
<search-item label="所属工会">
<el-select v-model="pageForm.unionId" clearable filterable placeholder="请选择所属工会"
style="width: 100%" @change="flushUnits" @clear="flushUnits">
<el-option v-for="item in unions" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="所属单位">
<el-select v-model="pageForm.unitId" clearable filterable placeholder="请选择所属单位" style="width: 100%">
<el-option v-for="item in units" :key="item.id" :label="item.name" :value="item.id"></el-option>
</el-select>
</search-item>
<search-item label="在职状态">
<dict-select v-model="pageForm.userState" code="USER_STATE" clearable placeholder="请选择在职状态"></dict-select>
</search-item>
<search-item label="人员类型">
<dict-select v-model="pageForm.personType" code="USER_PERSON_TYPE" clearable placeholder="请选择人员类型"></dict-select>
</search-item>
<search-item label="变更来源">
<el-select v-model="pageForm.changeOrigin" clearable filterable placeholder="请选择变更来源" style="width: 100%">
<el-option v-for="item in changeOriginData" :key="item.name"
:label="item.changeOriginName" :value="item.name"></el-option>
</el-select>
</search-item>
<search-item label="变更日期">
<el-date-picker v-model="pageForm.changeDateRange" type="daterange" value-format="yyyy-MM-dd"
start-placeholder="开始日期" end-placeholder="结束日期" range-separator="-"
style="width: 100%" @change="changeDateRangeChange"></el-date-picker>
</search-item>
</search>
</el-card>
<el-card shadow="never" class="mt10">
<table-tool label="待确认人员记录"></table-tool>
<el-table ref="table" :data="tableData" :size="tableSize" row-key="id"
style="width: 100%" @sort-change="pageOrder">
<el-table-column type="index" label="序号" width="70" align="center" :index="indexMethod"></el-table-column>
<el-table-column prop="loginname" label="工号" min-width="110" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column prop="username" label="姓名" min-width="100" sortable="custom" show-overflow-tooltip></el-table-column>
<el-table-column prop="sex" label="性别" width="80" align="center">
<template slot-scope="{row}">
<dict-tag code="USER_SEX" :value="row.sex"></dict-tag>
</template>
</el-table-column>
<el-table-column prop="userState" label="在职状态" min-width="100">
<template slot-scope="{row}">
<dict-tag code="USER_STATE" :value="row.userState"></dict-tag>
</template>
</el-table-column>
<el-table-column prop="personType" label="人员类型" min-width="110">
<template slot-scope="{row}">
<dict-tag code="USER_PERSON_TYPE" :value="row.personType"></dict-tag>
</template>
</el-table-column>
<el-table-column prop="unionName" label="所属工会" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column prop="unitName" label="所属单位" min-width="160" show-overflow-tooltip></el-table-column>
<el-table-column prop="changeTime" label="待确认时间" width="170" sortable="custom"></el-table-column>
<el-table-column prop="changeOrigin" label="变更来源" min-width="120">
<template slot-scope="{row}">{{ getChangeOrigin(row.changeOrigin) }}</template>
</el-table-column>
<el-table-column prop="remark" label="备注" min-width="150" show-overflow-tooltip></el-table-column>
<el-table-column label="操作" width="120" fixed="right" align="center">
<template slot-scope="{row}">
<el-button type="primary" size="mini" @click="openConfirm(row)">确认人员</el-button>
</template>
</el-table-column>
</el-table>
<!--#include("/layouts/pagination.html"){}#-->
</el-card>
<el-dialog title="确认人员" :visible.sync="confirmVisible" width="520px" append-to-body
:close-on-click-modal="false" @closed="resetConfirmForm">
<el-form ref="confirmFormRef" :model="confirmForm" :rules="confirmRules" label-width="100px">
<el-form-item label="异动类型" prop="changeType">
<el-select v-model="confirmForm.changeType" filterable placeholder="请选择异动类型" style="width: 100%">
<el-option v-for="item in finalChangeTypeData" :key="item.code"
:label="item.changeTypeName" :value="item.code"></el-option>
</el-select>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="confirmForm.remark" type="textarea" :rows="4" maxlength="1000"
show-word-limit placeholder="请输入备注"></el-input>
</el-form-item>
</el-form>
<template slot="footer">
<el-button @click="confirmVisible = false">取消</el-button>
<el-button type="primary" :loading="confirmLoading" @click="submitConfirm">确定</el-button>
</template>
</el-dialog>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
mixins: [initTableMixins],
data() {
return {
pageForm: {
searchKeyword: "",
unionId: "",
unitId: "",
userState: "",
personType: "",
changeOrigin: "",
changeDateRange: [],
changeDateBefore: "",
changeDateEnd: ""
},
unions: [],
units: [],
changeOriginData: [],
changeTypeData: [],
confirmVisible: false,
confirmLoading: false,
confirmForm: {
id: "",
changeType: "",
remark: ""
},
confirmRules: {
changeType: [{required: true, message: "请选择异动类型", trigger: "change"}],
remark: [{max: 1000, message: "备注不能超过1000个字符", trigger: "blur"}]
}
}
},
computed: {
finalChangeTypeData() {
return this.changeTypeData.filter((item) => item.code !== "PENDING_CONFIRM")
}
},
methods: {
/** 分页加载待确认人员,查询参数沿用人员变更记录页面。 */
pageData() {
this.$axios.post("/platform/sourcechange/pending/pageData", this.pageForm).then((resp) => {
if (resp.code === 0) {
this.tableData = resp.data.list
this.pageForm.totalCount = resp.data.totalCount
} else {
this.$message.warning(resp.msg)
}
})
},
/** 工会变更时重新加载其下属单位,避免带入其他工会的单位条件。 */
flushUnits() {
this.$set(this.pageForm, "unitId", "")
if (!this.pageForm.unionId) {
this.$businessTool.listUnit().then((data) => {
this.units = data
})
return
}
this.$businessTool.listUnit(this.pageForm.unionId).then((data) => {
this.units = data
})
},
/** 将日期组件值转换成后台通用的起止日期参数。 */
changeDateRangeChange(value) {
this.pageForm.changeDateBefore = value && value.length ? value[0] : ""
this.pageForm.changeDateEnd = value && value.length ? value[1] : ""
},
/** 根据枚举数据展示变更来源名称。 */
getChangeOrigin(value) {
const option = this.changeOriginData.find((item) => item.name === value)
return option ? option.changeOriginName : value
},
/** 打开确认弹窗并绑定当前待确认历史记录。 */
openConfirm(row) {
this.confirmForm.id = row.id
this.confirmForm.changeType = ""
this.confirmForm.remark = row.remark || ""
this.confirmVisible = true
},
/** 提交最终异动类型,成功后刷新列表使已确认人员立即移除。 */
submitConfirm() {
this.$refs.confirmFormRef.validate((valid) => {
if (!valid) return
this.confirmLoading = true
this.$axios.post("/platform/sourcechange/pending/confirm", {
data: JSON.stringify(this.confirmForm)
}).then((resp) => {
if (resp.code === 0) {
this.$message.success("人员确认成功")
this.confirmVisible = false
this.pageData()
} else {
this.$message.warning(resp.msg)
}
}).finally(() => {
this.confirmLoading = false
})
})
},
/** 关闭弹窗后清理表单校验状态及业务字段。 */
resetConfirmForm() {
this.confirmForm = {id: "", changeType: "", remark: ""}
if (this.$refs.confirmFormRef) {
this.$refs.confirmFormRef.clearValidate()
}
},
/** 加载当前登录人可用的组织及异动枚举数据。 */
initOptions() {
Promise.all([
this.$businessTool.listUnion(),
this.$businessTool.listUnit(),
this.$businessTool.getEnumOptions("MemberChangeType"),
this.$businessTool.getEnumOptions("MemberChangeOrigin")
]).then((result) => {
this.unions = result[0]
this.units = result[1]
this.changeTypeData = result[2]
this.changeOriginData = result[3]
this.pageData()
})
}
},
created() {
this.initOptions()
}
})
</script>
<!--#
}
#-->