人员管理、民主管理、主页优化

This commit is contained in:
2026-10-30 17:49:33 +08:00
parent 7dacfd7e5a
commit 8960d0e723
33 changed files with 296 additions and 111 deletions
@@ -12,7 +12,7 @@ const act = {
<div class="swiper-slide" v-for="(activity, index) in actList" :key="activity.id">
<div class="item" role="button" tabindex="0" @click="go(activity)" @keydown.enter="go(activity)" @keydown.space.prevent="go(activity)">
<div class="img-box">
<el-image :src="activity.cover" fit="cover" :alt="activity.name">
<el-image :src="activity.cover" fit="contain" :alt="activity.name">
<div slot="error" class="portal-cover-empty"><i class="fa fa-picture-o" aria-hidden="true"></i><span>暂无图片</span></div>
</el-image>
<span class="status" :class="{'status-ended': getStatusText(activity) === '已结束', 'status-upcoming': getStatusText(activity) === '未开始'}">
@@ -356,12 +356,9 @@ const act = {
height: 100% !important;
max-width: 100% !important;
max-height: 128px !important;
object-fit: fill !important;
transition: transform 0.3s ease;
}
.activity-swiper .swiper-slide .item:hover .img-box img {
transform: scale(1.1);
/* 活动海报含有文字,等比完整显示且悬停时不放大,避免内容被裁切。 */
object-fit: contain !important;
object-position: center;
}
.activity-swiper .swiper-slide .item h4 {
@@ -5,7 +5,7 @@ const entry = {
<div class="portal-entry-tabs" role="tablist" aria-label="推荐入口">
<button v-for="section in entrySections" :key="section.key"
type="button" role="tab" :aria-selected="activeSection === section.key"
:class="{active: activeSection === section.key}" @click="$set(this, 'activeSection', section.key)">{{ section.title }}</button>
:class="{active: activeSection === section.key}" @click="switchSection(section.key)">{{ section.title }}</button>
</div>
<a class="portal-more" href="/platform/v4/apps">全部应用 <i class="fa fa-arrow-right" aria-hidden="true"></i></a>
</div>
@@ -60,6 +60,10 @@ const entry = {
this.getFavorite()
},
methods: {
// sectionKey 为 serv(推荐服务)、app(推荐应用)或 fav(我的收藏);通过组件方法更新栏目,避免内联事件中 this 指向错误。
switchSection(sectionKey) {
this.$set(this, 'activeSection', sectionKey)
},
// platform 固定传 PC;Result.data 为当前用户有权限的推荐服务数组。
getRecommendService() {
this.$axios.post('/platform/home/listRecommendService', {platform: "PC"}).then(res => {
@@ -118,7 +118,7 @@ layout("/layouts/v4/baseLayout.html"){
</style>
<link rel="stylesheet" href="${base!}/assets/platform/css/home-portal.css?v=20261028-2" />
<link rel="stylesheet" href="${base!}/assets/platform/css/home-portal.css?v=20261030-1" />
<!-- 登录资料仅在 HTML 属性中输出并转义;放在 Vue 挂载区域外,避免名称被当作模板表达式解析。 -->
<div id="v4-home-profile-data" hidden
@@ -155,14 +155,13 @@ layout("/layouts/platform.html"){
</el-button>
<el-button @click="$refs.sortRef.onOpen()" size="medium" type="primary" icon="el-icon-sort">排序
</el-button>
<el-button v-if="$auth.hasPermission('sys.manager.role.user')" size="medium" type="primary"
icon="el-icon-user" :loading="memberRoleLoading" @click="doSettingMemberRole">
一键设置会员角色
</el-button>
</div>
</el-row>
<!-- <div class="pull-right offscreen-right mt5 ml5">-->
<!-- <el-button size="medium" @click="doSettingMemberRole" type="primary"><i class="el-icon-s-tools"></i>-->
<!-- 一键设会员角色-->
<!-- </el-button>-->
<!-- </div>-->
<!-- <div class="pull-right offscreen-right mt5 ml5">-->
<!-- <el-button size="medium" @click="doPublic" type="primary">一键设置公共角色</el-button>-->
<!-- </div>-->
@@ -511,6 +510,7 @@ layout("/layouts/platform.html"){
}
}
return {
memberRoleLoading: false,
addDialogVisible: false,
editDialogVisible: false,
roleDialogVisible: false,
@@ -689,18 +689,30 @@ layout("/layouts/platform.html"){
})
},
doSettingMemberRole() {
this.$confirm("是否确定一键设置会员角色?", "提示", {
if (this.memberRoleLoading) {
return
}
// 操作面向全部会员,忽略当前列表筛选;确认期间也锁定按钮,避免重复提交。
this.$set(this, "memberRoleLoading", true)
this.$confirm("确定为全部已标记为会员的人员设置会员角色吗?已有角色将保留。", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(async () => {
const {code, msg} = await this.$axios.post("/platform/sys/role/doSettingMemberRole")
if (code === 0) {
this.$message.success(msg)
}
.then(() => {
return this.$axios.post("/platform/sys/role/doSettingMemberRole").then((res) => {
if (res.code === 0) {
this.$message.success("设置完成:新增 " + res.data.addedCount
+ " 条,恢复启用 " + res.data.enabledCount + " 条会员角色关联")
this.pageData()
}
})
})
.catch(() => {
// 取消确认无需提示;请求异常由全局 axios 拦截器统一提示。
})
.finally(() => {
this.$set(this, "memberRoleLoading", false)
})
},
formatAt(val) {
@@ -9,8 +9,8 @@ layout("/layouts/platform.html"){
<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 @keyup.enter.native="doSearch" clearable placeholder="请输入会议名称" v-model="pageForm.searchKeyword"></el-input>
<search-item label="资料名称">
<el-input @keyup.enter.native="doSearch" clearable placeholder="请输入资料名称" v-model="pageForm.searchKeyword"></el-input>
</search-item>
</search>
</el-card>
@@ -124,7 +124,7 @@ layout("/layouts/platform.html"){
</el-descriptions-item>
<el-descriptions-item label="入职时间">
<el-form-item prop="arrivalAtSchoolDate">
<el-input v-model="formData.arrivalAtSchoolDate" placeholder="请输入入职时间"
<el-input v-model="formData.arrivalAtSchoolDate" placeholder="暂无"
disabled maxlength="50"></el-input>
</el-form-item>
</el-descriptions-item>
@@ -256,7 +256,6 @@ layout("/layouts/platform.html"){
personalData: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
specialty: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
marriage: [{ required: true, message: "必填", trigger: ["change", "blur"] }],
arrivalAtSchoolDate: [{ required: true, message: "必填", trigger: ["change", "blur"] }]
/*email: [
{
validator: (rule, value, callback) => {
@@ -321,6 +320,14 @@ layout("/layouts/platform.html"){
}
},
methods: {
// 缺失或非法日期回填为空,避免生成十二位 Invalid date;不使用当天日期补缺。
formatArrivalAtSchoolDate(value) {
if (value === null || value === undefined || String(value).trim() === '') {
return ''
}
const date = this.$moment(value, this.$moment.ISO_8601, true)
return date.isValid() ? date.format('YYYY-MM-DD') : ''
},
normalizeUnitField() {
if (!this.formData || !this.formData.unitId) {
return
@@ -413,6 +420,7 @@ layout("/layouts/platform.html"){
debugger
if (res.code === 0) {
this.formData = res.data
this.$set(this.formData, "arrivalAtSchoolDate", this.formatArrivalAtSchoolDate(res.data.arrivalAtSchoolDate))
}
} else {
const {
@@ -468,7 +476,7 @@ layout("/layouts/platform.html"){
this.$set(this.formData, "email", email)
this.$set(this.formData, "families", families ? families : [])
this.$set(this.formData, "personalData", personalData)
this.$set(this.formData, "arrivalAtSchoolDate", this.$moment(arrivalAtSchoolDate).format('YYYY-MM-DD'))
this.$set(this.formData, "arrivalAtSchoolDate", this.formatArrivalAtSchoolDate(arrivalAtSchoolDate))
}
}
},
@@ -23,8 +23,9 @@ const INFO = {
<el-descriptions-item label="工作单位">{{ viewData.unitName }}</el-descriptions-item>
<el-descriptions-item label="所属工会">{{ viewData.unionName }}</el-descriptions-item>
<el-descriptions-item v-if="showThreeUnit" label="三级单位">{{ viewData.threeUnitName || '暂无' }}</el-descriptions-item>
<el-descriptions-item v-else label="所属校区">{{ viewData.campus }}</el-descriptions-item>
<!-- 屏蔽三级单位展示,所属校区仍遵循原有显示条件。 -->
<el-descriptions-item v-if="false" label="三级单位">{{ viewData.threeUnitName || '暂无' }}</el-descriptions-item>
<el-descriptions-item v-if="!showThreeUnit" label="所属校区">{{ viewData.campus }}</el-descriptions-item>
<el-descriptions-item label="身份证号码">{{ viewData.idCard }}</el-descriptions-item>
<el-descriptions-item label="联系电话">{{ viewData.mobile }}</el-descriptions-item>
@@ -74,7 +75,8 @@ const INFO = {
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="变更信息" name="changeInfo" v-if="viewData.changeInfos">
<el-table :data="viewData.changeInfos" :size="tableSize" @sort-change="pageOrder" ref="table"
<!-- 仅过滤展示数据,保留后台三级单位历史变更记录。 -->
<el-table :data="(viewData.changeInfos || []).filter(item => item.field !== 'threeUnitId' && item.field !== 'threeUnitName' && item.fieldName !== '三级单位')" :size="tableSize" @sort-change="pageOrder" ref="table"
row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" align="center" header-align="center"
label="序号" type="index" width="80px"></el-table-column>
@@ -67,7 +67,8 @@ const MEMBER_ALL_CHANGE_INFO = {
:key="index" :timestamp="changeData.timestamp">
<el-card>
<h4>{{ changeData.changeOriginName }}</h4>
<el-table :data="changeData.changeInfos" size="mini" ref="table" row-key="id" style="width: 100%">
<!-- 仅过滤展示数据,保留后台三级单位历史变更记录。 -->
<el-table :data="(changeData.changeInfos || []).filter(item => item.field !== 'threeUnitId' && item.field !== 'threeUnitName' && item.fieldName !== '三级单位')" size="mini" ref="table" row-key="id" style="width: 100%">
<el-table-column align="center" header-align="center"
label="序号" type="index" width="80px"></el-table-column>
<el-table-column prop="fieldName" label="变更字段" header-align="center"></el-table-column>
@@ -86,6 +87,7 @@ const MEMBER_ALL_CHANGE_INFO = {
</el-timeline-item>
</el-timeline>
</el-tab-pane>
<slot></slot>
</el-tabs>
`,
store,
@@ -101,7 +101,8 @@ const MEMBER_CHANGE = {
</el-form-item>
</el-descriptions-item>
</template>
<el-descriptions-item v-if="showThreeUnit" label="三级单位">
<!-- 屏蔽三级单位编辑,保留回填值,避免提交其他变更时清空历史数据。 -->
<el-descriptions-item v-if="false" label="三级单位">
<el-form-item prop="threeUnitId">
<el-select v-model="formData.threeUnitId" clearable filterable
placeholder="请选择三级单位" style="width: 100%">
@@ -110,7 +111,7 @@ const MEMBER_CHANGE = {
</el-select>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item v-else label="所属校区">
<el-descriptions-item v-if="!showThreeUnit" label="所属校区">
<el-form-item prop="campus">
<dict-select style="width: 100%" placeholder="请选择所属校区" v-model="formData.campus"
:disabled="allowFields('campus')" code="USER_CAMPUS"></dict-select>
@@ -215,8 +216,6 @@ const MEMBER_CHANGE = {
value-format="yyyy-MM-dd"></el-date-picker>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<el-descriptions-item></el-descriptions-item>
<template v-if="formData.loginname == $store.state.user.loginname">
<el-descriptions-item label="家庭主要成员" :span="3">
<el-form-item prop="families">
@@ -393,31 +392,6 @@ const MEMBER_CHANGE = {
allowFields(prop) {
return !this.allowChangeFields.map(v => v.code).includes(prop)
},
// 管理页仅查询当前被编辑人员所属二级单位的直属三级单位,避免越级选择其他单位数据。
initThreeUnits() {
this.threeUnits = []
if (!this.showThreeUnit) {
return Promise.resolve()
}
if (!this.formData.unitId) {
this.$message.warning("当前人员未配置所属单位,无法查询三级单位")
return Promise.resolve()
}
return this.$axios.post("/platform/sys/unit/child", {pid: this.formData.unitId})
.then((resp) => {
if (resp.code === 0) {
this.threeUnits = resp.data || []
if (this.threeUnits.length === 0) {
this.$message.warning("当前所属单位未配置三级单位")
}
} else {
this.$message.error(resp.msg || "三级单位查询失败")
}
})
.catch(() => {
this.$message.error("三级单位查询失败,请稍后重试")
})
},
doSave(){
this.$confirm("保存后可在我的申请里面再次编辑,您确定要保存吗?", "提示", { type: "warning" })
.then(() => {
@@ -461,7 +435,7 @@ const MEMBER_CHANGE = {
this.units = await this.$businessTool.listUnit()
}
this.normalizeUnitField()
this.initThreeUnits()
// 三级单位已屏蔽,不再加载选项或提示配置缺失;原值继续随表单回填。
},
async getUserById(userId){
const resp = await $.post("/platform/member/change/apply/getUserByIdForMemberChange", { userId })
@@ -1,4 +1,4 @@
<!--#
<!--#
layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
@@ -22,7 +22,8 @@ layout("/layouts/platform.html"){
v-for="item in units"></el-option>
</el-select>
</search-item>
<search-item label="三级单位">
<!-- 三级单位已屏蔽,保留字段结构便于维护。 -->
<search-item label="三级单位" v-if="false">
<el-select clearable filterable placeholder="请选择三级单位" style="width: 100%"
v-model="pageForm.threeUnitId">
<el-option :key="item.id" :label="item.name" :value="item.id"
@@ -603,6 +604,8 @@ layout("/layouts/platform.html"){
// 分页和导出共用查询参数,排除已屏蔽的人员属性条件。
buildQueryPageForm(source = this.pageForm) {
const pageForm = clone(source)
// 隐藏的三级单位不参与列表查询和导出筛选。
pageForm.threeUnitId = ""
// 人员属性已屏蔽,查询和导出均不再按该字段过滤。
pageForm.userAttribute = ""
pageForm.userAttributes = "[]"
@@ -700,24 +703,10 @@ layout("/layouts/platform.html"){
})
}
},
// 所属单位变化时只加载其直属三级单位,避免跨单位筛选。
flushThreeUnits(unitId) {
// 三级单位已屏蔽,切换所属单位时仅清空旧筛选条件,不再请求子单位。
flushThreeUnits() {
this.$set(this.pageForm, "threeUnitId", null)
this.threeUnits = []
if (!unitId) {
return
}
this.$axios.post("/platform/sys/unit/child", {pid: unitId})
.then((res) => {
if (res.code === 0) {
this.threeUnits = res.data || []
} else {
this.$message.error(res.msg || "三级单位查询失败")
}
})
.catch(() => {
this.$message.error("三级单位查询失败,请稍后重试")
})
},
checkAll() {
this.checkedFields = this.tableColumns.map(c => c.prop);
@@ -75,7 +75,7 @@ layout("/layouts/platform.html"){
{ prop: "unitName", label: "所属单位", sortable: true },
{ prop: "changeTypes", label: "变更类型", sortable: true, width: 200 },
{ prop: "applyDateTime", label: "申请时间", sortable: true },
{ prop: "curTaskName", label: "当前节点"},
{ prop: "taskName", label: "当前节点"},
{ prop: "instanceState", label: "流程状态"}
],
changeTypeData: [],
@@ -427,8 +427,10 @@
},
getUnionName(val){
const data = this.units.find(v => v.id === val)
this.$set(this.formData, 'unionName', data ? data.unionname : '')
// 切换目标单位时同步名称;ID 类型统一后匹配,避免提交原单位名称。
const data = this.units.find(v => String(v.id) === String(val))
this.$set(this.formData, 'unitName', data ? data.name : '')
this.$set(this.formData, 'unionName', data ? (data.unionName || data.unionname || '') : '')
},
allowFields(prop) {
return !this.allowChangeFields.map(v => v.code).includes(prop)
@@ -432,8 +432,10 @@ layout("/layouts/platform.html"){
// 获取表单工会名称
getUnionName(val){
const data = this.units.find(v => v.id === val)
this.$set(this.formData, 'unionName', data ? data.unionName : '')
// 切换目标单位时同步名称;ID 类型统一后匹配,避免提交原单位名称。
const data = this.units.find(v => String(v.id) === String(val))
this.$set(this.formData, 'unitName', data ? data.name : '')
this.$set(this.formData, 'unionName', data ? (data.unionName || data.unionname || '') : '')
},
// 获取表单可编辑的字段信息
allowFields(prop) {
@@ -14,7 +14,7 @@
<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.unitName }}</el-descriptions-item>
<el-descriptions-item label="所属工会">{{ viewData.unionname }}</el-descriptions-item>
<el-descriptions-item label="所属校区">{{ viewData.campus }}</el-descriptions-item>
@@ -60,7 +60,8 @@
</el-descriptions>
</el-tab-pane>
<el-tab-pane label="变更信息" name="changeInfo" v-if="viewData.changeInfos">
<el-table :data="viewData.changeInfos" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<!-- 仅过滤展示数据,保留后台三级单位历史变更记录。 -->
<el-table :data="(viewData.changeInfos || []).filter(item => item.field !== 'threeUnitId' && item.field !== 'threeUnitName' && item.fieldName !== '三级单位')" :size="tableSize" @sort-change="pageOrder" ref="table" row-key="id" style="width: 100%">
<el-table-column :index="indexMethod" align="center" header-align="center"
label="序号" type="index" width="80px"></el-table-column>
<el-table-column prop="fieldName" label="变更字段" header-align="center"></el-table-column>
@@ -404,6 +404,14 @@ layout("/layouts/platform_h5.html"){
}
},
methods: {
// 缺失或非法日期回填为空,避免生成十二位 Invalid date;不使用当天日期补缺。
formatArrivalAtSchoolDate(value) {
if (value === null || value === undefined || String(value).trim() === '') {
return ''
}
const date = this.$moment(value, this.$moment.ISO_8601, true)
return date.isValid() ? date.format('YYYY-MM-DD') : ''
},
handlePageBack() {
if (window.h5HistoryLayerManager.stack.length) {
window.h5HistoryLayerManager.close()
@@ -592,6 +600,7 @@ layout("/layouts/platform_h5.html"){
.then((res) => {
if (res.code === 0) {
this.$set(this, "formData", res.data)
this.$set(this.formData, "arrivalAtSchoolDate", this.formatArrivalAtSchoolDate(res.data.arrivalAtSchoolDate))
}
})
}
@@ -649,7 +658,7 @@ layout("/layouts/platform_h5.html"){
this.$set(this.formData, "email", email)
this.$set(this.formData, "families", families ? families : [])
this.$set(this.formData, "personalData", personalData)
this.$set(this.formData, "arrivalAtSchoolDate", this.$moment(arrivalAtSchoolDate).format("YYYY-MM-DD"))
this.$set(this.formData, "arrivalAtSchoolDate", this.formatArrivalAtSchoolDate(arrivalAtSchoolDate))
// 处理校区信息
if (campus) {
@@ -133,6 +133,7 @@ const home = {
</div>
</div>
<!-- 暂停展示我的课堂,保留模板供后续恢复。
<div class="classroom-section">
<div class="classroom-section__head">
<div class="classroom-section__title">我的课堂</div>
@@ -192,6 +193,9 @@ const home = {
<div v-else-if="!classroomLoading" class="classroom-empty">暂无课程</div>
</div>
-->
<!-- 暂停展示政策文件,待接入内容后恢复。
<div class="policy-panel">
<div class="entry-panel__heading">
<span class="entry-panel__icon entry-panel__icon--policy"><van-icon name="description"></van-icon></span>
@@ -203,6 +207,8 @@ const home = {
</div>
</div>
-->
<div class="act-list" v-if="showLatestActivity">
<div class="section-title section-title--hidden">最新活动</div>
<template v-if="activityOptions && activityOptions.length > 0">
@@ -276,6 +282,7 @@ const home = {
className: "feature-card--model",
href: "/platform/honor/manage/h5"
},
/* 暂停展示普惠信息,保留入口配置供后续接入。
{
name: "普惠信息",
desc: "普惠服务信息",
@@ -284,6 +291,7 @@ const home = {
className: "feature-card--inclusive",
href: ""
}
*/
],
appLogo: "",
appName: "",
@@ -613,8 +621,9 @@ const home = {
created() {
this.listHomeBrand()
this.listRecommendApp()
this.listClassroomCourses()
this.listClassroomRecommendOptions()
// 我的课堂暂停展示,同步停用课程及推荐标签请求,恢复模块时再启用。
// this.listClassroomCourses()
// this.listClassroomRecommendOptions()
this.listSpreadHomeContent()
if (this.showLatestActivity) {
this.listActivity()
@@ -900,7 +909,8 @@ const home = {
margin: 0 12px 7px;
display: grid;
grid-template-columns: 1.08fr 1fr;
grid-template-rows: 86px 86px 92px;
/* 普惠入口暂停展示,取消其第三行占位,避免留下空白。 */
grid-template-rows: 86px 86px;
gap: 8px;
}