Merge remote-tracking branch 'origin/feature_会员模块UI优化' into release_20260831
This commit is contained in:
+2
-1
@@ -72,7 +72,8 @@ public class MemberInfoBoardController {
|
||||
List<Map> result = new ArrayList<>();
|
||||
int year = DateUtil.thisYear();
|
||||
for (int i = year - 5; i < year; i++) {
|
||||
int count = memberInfoService.count(Sqls.create("select count(1) from member_history where year = @year ").setParam("year", year));
|
||||
// 历史趋势必须按循环中的年份分别统计,避免五个历史节点都查询成当前年份。
|
||||
int count = memberInfoService.count(Sqls.create("select count(1) from member_history where year = @year ").setParam("year", i));
|
||||
result.add(Map.of("label", i, "value", count));
|
||||
}
|
||||
result.add(Map.of("label", year, "value", memberInfoService.count(Sqls.create("select count(1) from sys_user where member = 1"))));
|
||||
|
||||
@@ -245,6 +245,8 @@
|
||||
//初始化pjax
|
||||
;(function initPjax() {
|
||||
if ($.support.pjax) {
|
||||
// jquery-pjax 的历史缓存读取全局默认值;必须在初始化前关闭,避免返回时恢复缺少 Vue 动态样式的旧 DOM。
|
||||
$.pjax.defaults.maxCacheLength = 0
|
||||
$(document).pjax("a[data-pjax]", "#container", {
|
||||
maxCacheLength: 0,
|
||||
push: true,
|
||||
@@ -271,22 +273,9 @@
|
||||
toggleShowBar()
|
||||
})
|
||||
|
||||
// 监听浏览器的前进和后退操作
|
||||
// PJAX 已内置页面前进、后退处理;这里只同步 H5 弹层历史,禁止再次发起 PJAX 请求。
|
||||
$(window).on("popstate", function (event) {
|
||||
if (window.h5HistoryLayerManager.handlePopState(event.originalEvent)) {
|
||||
return
|
||||
}
|
||||
if (event.originalEvent.state) {
|
||||
// 如果存在历史记录状态,触发 Pjax 加载对应内容
|
||||
$.pjax({
|
||||
url: event.originalEvent.state.url,
|
||||
container: "#container",
|
||||
fragment: "#container",
|
||||
timeout: 8000,
|
||||
push: false,
|
||||
scrollTo: false
|
||||
})
|
||||
}
|
||||
window.h5HistoryLayerManager.handlePopState(event.originalEvent)
|
||||
})
|
||||
}
|
||||
})()
|
||||
|
||||
+365
-52
@@ -1,49 +1,326 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="入会分工会审核" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<van-sticky>
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
placeholder="请输入工号或者姓名进行查询"
|
||||
show-action
|
||||
:reverse-color="false"
|
||||
input-align="left"
|
||||
@search="doSearch">
|
||||
<template #action>
|
||||
<div @click="doSearch">搜索</div>
|
||||
</template>
|
||||
</van-search>
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<van-dropdown-item :options="unitList" @change="doSearch" v-model="pageForm.unitId"></van-dropdown-item>
|
||||
<van-dropdown-item :options="auditList" @change="doSearch" v-model="pageForm.audit"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
<style id="style-member-branch-approval-h5">
|
||||
<!--#include("../../theme.css"){}#-->
|
||||
|
||||
<table-list api="/platform/member/apply/branchUnionApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="userName" @ready="doSearch">
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-audit-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-audit-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.member-audit-page .van-nav-bar__title {
|
||||
color: #172033;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-audit-page .van-nav-bar .van-icon,
|
||||
.member-audit-page .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.member-audit-sticky {
|
||||
padding: 22px 12px 1px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-audit-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.member-audit-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.member-audit-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-audit-search .van-field__control::placeholder {
|
||||
color: #a7b0bf;
|
||||
}
|
||||
|
||||
.member-audit-filter {
|
||||
margin: 0 0 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.member-audit-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-menu__bar,
|
||||
.member-audit-filter .van-dropdown-menu__item,
|
||||
.member-audit-filter .van-dropdown-menu__title {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-menu__bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-menu__title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-menu__title--active,
|
||||
.member-audit-filter .van-dropdown-item__option--active,
|
||||
.member-audit-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-item__option {
|
||||
display: flex;
|
||||
min-height: 48px;
|
||||
padding: 0 16px;
|
||||
align-items: center;
|
||||
color: #46566c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-audit-content {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.member-audit-list .table-list-container {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.member-audit-list .empty-state {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.member-audit-empty {
|
||||
display: flex;
|
||||
min-height: 280px;
|
||||
padding: 46px 18px 36px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.member-audit-empty img {
|
||||
display: block;
|
||||
width: 86%;
|
||||
max-width: 290px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.member-audit-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-audit-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-audit-card-header {
|
||||
display: flex;
|
||||
margin-bottom: 7px;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.member-audit-card-heading {
|
||||
min-width: 0;
|
||||
padding-right: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.member-audit-card-title {
|
||||
overflow: hidden;
|
||||
color: #253247;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-audit-card-code {
|
||||
margin-top: 1px;
|
||||
color: #9ba6b6;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-audit-status {
|
||||
display: inline-flex;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.member-audit-status .van-tag {
|
||||
display: inline-flex;
|
||||
min-height: 24px;
|
||||
padding: 3px 9px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-audit-page .table-list-container .table-list-item .action-btn .van-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton {
|
||||
min-height: calc(100vh - 46px);
|
||||
padding: 22px 12px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton__filter,
|
||||
.member-audit-page-skeleton__card {
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .07);
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton__filter {
|
||||
min-height: 96px;
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton__card {
|
||||
min-height: 154px;
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
.member-audit-content,
|
||||
.member-audit-sticky {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<div class="member-h5-page member-audit-page">
|
||||
<van-nav-bar title="分工会审核" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<div class="member-audit-page-skeleton" v-if="pageLoading">
|
||||
<div class="member-audit-page-skeleton__filter"><van-skeleton title :row="2"></van-skeleton></div>
|
||||
<div class="member-audit-page-skeleton__cards">
|
||||
<div class="member-audit-page-skeleton__card" v-for="index in 3" :key="'branch-page-skeleton-' + index">
|
||||
<van-skeleton title :row="4"></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="!pageLoading">
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="member-audit-sticky">
|
||||
<van-search v-model="pageForm.searchKeyword" class="member-audit-search"
|
||||
placeholder="请输入工号或姓名搜索" shape="round" clearable
|
||||
@search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="member-audit-filter" :class="{'is-open': filterOpened}"
|
||||
active-color="#1989fa" :close-on-click-outside="false"
|
||||
:close-on-click-overlay="false">
|
||||
<van-dropdown-item v-model="pageForm.unitId" :options="unitList" @change="doSearch"
|
||||
@open="setFilterOpened(true)" @close="setFilterOpened(false)"></van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.audit" :options="auditList" @change="doSearch"
|
||||
@open="setFilterOpened(true)" @close="setFilterOpened(false)"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<main class="member-audit-content">
|
||||
<div class="member-audit-list">
|
||||
<div v-if="pageForm.totalCount === 0" class="member-audit-empty">
|
||||
<img src="/assets/mobile/img/home/v4/app-center-empty-v4.png" alt="暂无分工会审核数据">
|
||||
<div class="member-audit-empty__title">暂无审核数据</div>
|
||||
<div class="member-audit-empty__hint">当前筛选条件下没有需要办理的入会申请</div>
|
||||
</div>
|
||||
<table-list v-show="!initialLoading" api="/platform/member/apply/branchUnionApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="userName" :show_loading_overlay="false" @loading-change="onListLoadingChange" @ready="onReady">
|
||||
<template #header="{index,row}">
|
||||
<div class="member-audit-card-header">
|
||||
<div class="member-audit-card-heading">
|
||||
<div class="member-audit-card-title">{{row.userName || '--'}}</div>
|
||||
<div class="member-audit-card-code">工号:{{row.loginName || '--'}}</div>
|
||||
</div>
|
||||
<enum-tag class="member-audit-status" v-if="row.instanceState" :value="row.instanceState"
|
||||
name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="工号">{{row.loginName}}</table-column>
|
||||
<table-column label="所属工会">{{row.unionName}}</table-column>
|
||||
<table-column label="工作单位">{{row.unitName}}</table-column>
|
||||
<table-column label="填报时间">{{row.applyDateTime}}</table-column>
|
||||
<table-column label="当前节点">{{row.curTaskName}}</table-column>
|
||||
<table-column label="所属工会">{{row.unionName || '--'}}</table-column>
|
||||
<table-column label="工作单位">{{row.unitName || '--'}}</table-column>
|
||||
<table-column label="填报时间">{{row.applyDateTime || '--'}}</table-column>
|
||||
<table-column label="当前节点">{{row.curTaskName || '--'}}</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)">
|
||||
<i class="fa fa-check"></i>
|
||||
<van-icon name="edit"></van-icon>
|
||||
<span>审核</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-undo"></i>
|
||||
<van-icon name="revoke"></van-icon>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<info ref="infoRef">
|
||||
<div v-if="showApprovalForm">
|
||||
@@ -60,13 +337,15 @@ layout("/layouts/platform_h5.html"){
|
||||
show-word-limit
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(2)">拒绝</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
|
||||
<div class="member-approval-actions">
|
||||
<van-button class="member-agree-button" block :loading="formLoading" :disabled="formLoading" @click="handleTaskAction(1)">同意</van-button>
|
||||
<van-button type="danger" block :disabled="formLoading" @click="handleTaskAction(2)">拒绝</van-button>
|
||||
<van-button class="member-return-button" block :disabled="formLoading" @click="handleTaskAction(6)">退回</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</info>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../common/info.js"){}#-->
|
||||
@@ -83,6 +362,7 @@ layout("/layouts/platform_h5.html"){
|
||||
unitId: "",
|
||||
audit: false
|
||||
},
|
||||
unionList: [],
|
||||
unitList: [],
|
||||
auditList: [
|
||||
{ text: "已审核", value: true },
|
||||
@@ -91,27 +371,63 @@ layout("/layouts/platform_h5.html"){
|
||||
|
||||
// 审核相关
|
||||
formData: {},
|
||||
showApprovalForm: false
|
||||
showApprovalForm: false,
|
||||
initialLoading: true,
|
||||
formLoading: false,
|
||||
pageLoading: true,
|
||||
filterOpened: false,
|
||||
filterReady: false,
|
||||
tableReady: false,
|
||||
initialSearchStarted: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
"info": INFO
|
||||
},
|
||||
methods: {
|
||||
methods: {
|
||||
historyBack,
|
||||
|
||||
// 同步筛选弹层展开状态,用于保持与提案预审核一致的筛选栏圆角。
|
||||
setFilterOpened(opened) {
|
||||
this.$set(this, "filterOpened", opened)
|
||||
},
|
||||
|
||||
onReady() {
|
||||
this.$set(this, "tableReady", true)
|
||||
this.tryInitialSearch()
|
||||
},
|
||||
|
||||
// 工会、单位筛选项与列表组件都完成初始化后,只触发一次首次查询。
|
||||
tryInitialSearch() {
|
||||
if (!this.filterReady || !this.tableReady || this.initialSearchStarted) return
|
||||
this.$set(this, "initialSearchStarted", true)
|
||||
this.doSearch()
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
|
||||
onListLoadingChange(state) {
|
||||
if (state.initial) {
|
||||
this.$set(this, "initialLoading", state.loading)
|
||||
if (!state.loading && this.initialSearchStarted) {
|
||||
this.$set(this, "pageLoading", false)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
unionChange() {
|
||||
this.$set(this.pageForm, "unitId", null)
|
||||
this.flushUnits().then(() => {
|
||||
this.doSearch()
|
||||
})
|
||||
},
|
||||
|
||||
// 查看详情
|
||||
onView(row) {
|
||||
this.showApprovalForm = false
|
||||
@@ -127,18 +443,13 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
|
||||
async handleTaskAction(val) {
|
||||
await this.$refs.formRef.validate();
|
||||
this.$dialog.confirm({
|
||||
handleTaskAction(val) {
|
||||
if (this.formLoading) return
|
||||
this.$refs.formRef.validate().then(() => this.$dialog.confirm({
|
||||
title: "提示",
|
||||
message: "您确定要提交吗?"
|
||||
}).then(() => {
|
||||
const loading = this.$toast.loading({
|
||||
message: "加载中...",
|
||||
forbidClick: true,
|
||||
overlay: true,
|
||||
duration: 0
|
||||
})
|
||||
})).then(() => {
|
||||
this.formLoading = true
|
||||
this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
@@ -151,7 +462,7 @@ layout("/layouts/platform_h5.html"){
|
||||
this.doSearch()
|
||||
}
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
this.formLoading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -182,7 +493,7 @@ layout("/layouts/platform_h5.html"){
|
||||
initUnion() {
|
||||
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||
const unionId = hasAdmin ? null : this.$store.state.user.union.id
|
||||
this.$businessTool.listUnion(unionId).then((data) => {
|
||||
return this.$businessTool.listUnion(unionId).then((data) => {
|
||||
this.unionList = data
|
||||
this.unionList.forEach((v) => {
|
||||
v.text = v.name
|
||||
@@ -199,7 +510,7 @@ layout("/layouts/platform_h5.html"){
|
||||
flushUnits() {
|
||||
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||
const unionId = hasAdmin ? this.pageForm.unionId : this.$store.state.user.union.id
|
||||
this.$businessTool.listUnit(unionId).then((data) => {
|
||||
return this.$businessTool.listUnit(unionId).then((data) => {
|
||||
this.unitList = data
|
||||
this.unitList.forEach((v) => {
|
||||
v.text = v.name
|
||||
@@ -212,9 +523,11 @@ layout("/layouts/platform_h5.html"){
|
||||
})
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.initUnion()
|
||||
await this.flushUnits()
|
||||
created() {
|
||||
this.initUnion().then(() => this.flushUnits()).finally(() => {
|
||||
this.$set(this, "filterReady", true)
|
||||
this.tryInitialSearch()
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
const INFO = {
|
||||
template: /*language=HTML*/ `
|
||||
<van-action-sheet v-model="visible" title="查看详情">
|
||||
<div class="detail-container">
|
||||
<van-cell-group title="基本信息">
|
||||
<van-action-sheet v-model="visible" class="member-info-sheet" title="入会申请详情"
|
||||
:close-on-click-overlay="false" @close="handleComponentClose">
|
||||
<div class="member-info-scroll">
|
||||
<div class="member-list-skeleton" v-if="detailLoading">
|
||||
<div class="member-list-skeleton__card" v-for="index in 3" :key="'detail-skeleton-' + index">
|
||||
<van-skeleton title :row="5"></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<section class="member-detail-card">
|
||||
<div class="member-detail-card__title">基本信息</div>
|
||||
<van-cell-group :border="false">
|
||||
<van-cell title="工号">{{ viewData.loginname }}</van-cell>
|
||||
<van-cell title="姓名">{{ viewData.username }}</van-cell>
|
||||
<van-cell title="性别">{{ viewData.sex }}</van-cell>
|
||||
@@ -73,9 +82,12 @@ const INFO = {
|
||||
</van-cell>
|
||||
|
||||
</van-cell-group>
|
||||
</section>
|
||||
|
||||
<template v-for="task in doneTasks">
|
||||
<van-cell-group :title="task.displayName" v-if="task.ext.isFirstTaskNode">
|
||||
<section class="member-detail-card" v-if="task.ext.isFirstTaskNode" :key="'task-' + task.id">
|
||||
<div class="member-detail-card__title">{{task.displayName}}</div>
|
||||
<van-cell-group :border="false">
|
||||
<van-cell title="申请用户">{{ task.ext.initiatorName }}({{task.ext.initiatorAccount}})
|
||||
</van-cell>
|
||||
<van-cell title="申请时间">{{ task.finishTime }}</van-cell>
|
||||
@@ -84,8 +96,11 @@ const INFO = {
|
||||
:value="task.ext.submitType"></dict-tag>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
|
||||
<van-cell-group :title="task.displayName" v-else>
|
||||
<section class="member-detail-card" v-else :key="'task-' + task.id">
|
||||
<div class="member-detail-card__title">{{task.displayName}}</div>
|
||||
<van-cell-group :border="false">
|
||||
<van-cell title="办理用户">{{ task.taskFormData.userName }}({{task.taskFormData.loginName}})
|
||||
</van-cell>
|
||||
<van-cell title="办理时间">{{ task.finishTime }}</van-cell>
|
||||
@@ -97,6 +112,8 @@ const INFO = {
|
||||
<div v-html="task.taskFormData.tf_opinion"></div>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
<slot></slot>
|
||||
@@ -109,36 +126,68 @@ const INFO = {
|
||||
row: {},
|
||||
viewData: {},
|
||||
doneTasks: [],
|
||||
detailLoading: false,
|
||||
historyUnsubscribe: null,
|
||||
historyLayerName: "member-apply-info"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 打开入会申请详情。
|
||||
* row 传列表当前申请记录,至少包含申请 id;无返回值,详情和已办任务并行加载。
|
||||
*/
|
||||
onOpen(row) {
|
||||
this.row = row
|
||||
this.visible = true
|
||||
this.info()
|
||||
this.getDoneTasks()
|
||||
this.$set(this, "row", row)
|
||||
window.h5HistoryLayerManager.ensureRegistered("member-apply-detail")
|
||||
window.h5HistoryLayerManager.open(this.historyLayerName)
|
||||
this.detailLoading = true
|
||||
Promise.all([this.info(), this.getDoneTasks()]).finally(() => {
|
||||
this.detailLoading = false
|
||||
})
|
||||
},
|
||||
|
||||
// 关闭
|
||||
onClose(){
|
||||
this.visible = false
|
||||
window.h5HistoryLayerManager.close(this.historyLayerName)
|
||||
},
|
||||
|
||||
handleComponentClose() {
|
||||
if (window.h5HistoryLayerManager.stack.includes(this.historyLayerName)) {
|
||||
window.h5HistoryLayerManager.close(this.historyLayerName)
|
||||
}
|
||||
},
|
||||
|
||||
// id 为入会申请记录主键;接口返回会员申请详情对象。
|
||||
info() {
|
||||
this.$axios.post("/platform/member/apply/mine/findMemberApplyRecord", { id: this.row.id }).then((res) => {
|
||||
return this.$axios.post("/platform/member/apply/mine/findMemberApplyRecord", { id: this.row.id }, {h5SkeletonLoading: true}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.viewData = res.data
|
||||
this.$set(this, "viewData", res.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
// bizId 为入会申请记录主键;接口返回该申请已完成的 WF 任务数组。
|
||||
getDoneTasks() {
|
||||
this.$axios.post("/flow/common/doneTasks", { bizId: this.row.id }).then((res) => {
|
||||
return this.$axios.post("/flow/common/doneTasks", { bizId: this.row.id }, {h5SkeletonLoading: true}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.doneTasks = res.data
|
||||
this.$set(this, "doneTasks", res.data)
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
window.h5HistoryLayerManager.ensureRegistered("member-apply-detail")
|
||||
this.historyUnsubscribe = window.h5HistoryLayerManager.subscribe((stack) => {
|
||||
this.$set(this, "visible", stack.includes(this.historyLayerName))
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.historyUnsubscribe) {
|
||||
this.historyUnsubscribe()
|
||||
}
|
||||
if (window.h5HistoryLayerManager.pageKey === "member-apply-detail") {
|
||||
window.h5HistoryLayerManager.unregister("member-apply-detail")
|
||||
}
|
||||
},
|
||||
style: /*language=CSS*/ `
|
||||
.column-cell {
|
||||
flex-direction: column;
|
||||
@@ -149,12 +198,11 @@ const INFO = {
|
||||
border-collapse: collapse;
|
||||
table-layout: auto;
|
||||
text-align: center;
|
||||
font-family: 'Arial', sans-serif;
|
||||
margin: 20px 0;
|
||||
margin: 10px 0 0;
|
||||
}
|
||||
.table-header {
|
||||
background-color: gray;
|
||||
color: white;
|
||||
background-color: #edf5ff;
|
||||
color: #4f6f98;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@@ -166,8 +214,10 @@ const INFO = {
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
.table-cell {
|
||||
padding: 10px 20px;
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px 6px;
|
||||
border: 1px solid #e8eef6;
|
||||
color: #596779;
|
||||
font-size: 11px;
|
||||
text-align: center;
|
||||
}
|
||||
`
|
||||
|
||||
+431
-60
@@ -1,62 +1,382 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style id="style-member-apply-mine-h5">
|
||||
<!--#include("../../theme.css"){}#-->
|
||||
|
||||
body {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-mine-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-mine-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.member-mine-page .van-nav-bar__title {
|
||||
color: #172033;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-mine-page .van-nav-bar .van-icon,
|
||||
.member-mine-page .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.member-mine-sticky {
|
||||
padding: 22px 12px 1px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-mine-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.member-mine-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.member-mine-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-mine-search .van-field__control::placeholder {
|
||||
color: #a7b0bf;
|
||||
}
|
||||
|
||||
.member-mine-filter {
|
||||
margin: 0 0 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.member-mine-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.member-mine-filter .van-dropdown-menu__bar {
|
||||
height: 44px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.member-mine-filter .van-dropdown-menu__item {
|
||||
height: 44px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.member-mine-filter .van-dropdown-menu__title {
|
||||
display: inline-flex;
|
||||
height: 44px;
|
||||
align-items: center;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.member-mine-filter .van-dropdown-menu__title--active,
|
||||
.member-mine-filter .van-dropdown-item__option--active,
|
||||
.member-mine-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.member-mine-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
}
|
||||
|
||||
.member-mine-filter .van-dropdown-item__option {
|
||||
display: flex;
|
||||
min-height: 48px;
|
||||
padding: 0 16px;
|
||||
align-items: center;
|
||||
color: #46566c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-mine-filter .van-dropdown-item__option .van-cell__title {
|
||||
display: flex;
|
||||
min-height: 20px;
|
||||
align-items: center;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.member-mine-content {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.member-mine-list {
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.member-mine-list .table-list-container {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.member-mine-list .empty-state {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.member-mine-empty {
|
||||
display: flex;
|
||||
min-height: 280px;
|
||||
padding: 46px 18px 36px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.member-mine-empty img {
|
||||
display: block;
|
||||
width: 86%;
|
||||
max-width: 290px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.member-mine-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.member-mine-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-mine-card-header {
|
||||
display: flex;
|
||||
margin-bottom: 7px;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.member-mine-card-heading {
|
||||
min-width: 0;
|
||||
padding-right: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.member-mine-card-title {
|
||||
overflow: hidden;
|
||||
color: #253247;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-mine-card-code {
|
||||
margin-top: 1px;
|
||||
color: #9ba6b6;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-mine-card-status {
|
||||
display: inline-flex;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.member-mine-card-status .van-tag,
|
||||
.member-mine-card-status--plain {
|
||||
display: inline-flex;
|
||||
min-height: 24px;
|
||||
padding: 3px 9px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-mine-card-status--plain {
|
||||
color: #1989fa;
|
||||
background-color: #eaf4ff;
|
||||
}
|
||||
|
||||
.member-mine-page .table-list-container .table-list-item .action-btn .van-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.member-mine-page-skeleton {
|
||||
min-height: calc(100vh - 46px);
|
||||
padding: 22px 12px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-mine-page-skeleton__filter,
|
||||
.member-mine-page-skeleton__card {
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .07);
|
||||
}
|
||||
|
||||
.member-mine-page-skeleton__filter {
|
||||
min-height: 96px;
|
||||
}
|
||||
|
||||
.member-mine-page-skeleton__card {
|
||||
min-height: 154px;
|
||||
}
|
||||
|
||||
.member-mine-page-skeleton .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
.member-mine-content,
|
||||
.member-mine-sticky {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-sticky>
|
||||
<van-nav-bar title="入会填报记录" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
placeholder="请输入工号或者姓名进行查询"
|
||||
show-action
|
||||
:reverse-color="false"
|
||||
input-align="left"
|
||||
@search="doSearch">
|
||||
<template #action>
|
||||
<div @click="doSearch">搜索</div>
|
||||
</template>
|
||||
</van-search>
|
||||
<van-dropdown-menu
|
||||
v-if="$auth.hasRoleOr('SYSADMIN,SCHOOL_UNION_ADMIN,BRANCH_UNION_CHAIRMAN')"
|
||||
:close-on-click-outside="false"
|
||||
:close-on-click-overlay="false"
|
||||
>
|
||||
<van-dropdown-item :options="unionList" @change="unionChange" v-model="pageForm.unionId"></van-dropdown-item>
|
||||
<van-dropdown-item :options="unitList" @change="doSearch" v-model="pageForm.unitId"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
<div class="member-h5-page member-mine-page">
|
||||
<van-nav-bar title="我的入会" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<div class="member-mine-page-skeleton" v-if="pageLoading">
|
||||
<div class="member-mine-page-skeleton__filter"><van-skeleton title :row="2"></van-skeleton></div>
|
||||
<div class="member-mine-page-skeleton__cards">
|
||||
<div class="member-mine-page-skeleton__card" v-for="index in 3" :key="'mine-page-skeleton-' + index">
|
||||
<van-skeleton title :row="4"></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="!pageLoading">
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="member-mine-sticky">
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
class="member-mine-search"
|
||||
placeholder="请输入工号或姓名搜索"
|
||||
shape="round"
|
||||
clearable
|
||||
@search="doSearch"
|
||||
@clear="doSearch">
|
||||
</van-search>
|
||||
<van-dropdown-menu
|
||||
v-if="$auth.hasRoleOr('SYSADMIN,SCHOOL_UNION_ADMIN,BRANCH_UNION_CHAIRMAN')"
|
||||
class="member-mine-filter"
|
||||
:class="{'is-open': filterOpened}"
|
||||
active-color="#1989fa"
|
||||
:close-on-click-outside="false"
|
||||
:close-on-click-overlay="false">
|
||||
<van-dropdown-item
|
||||
v-model="pageForm.unionId"
|
||||
:options="unionList"
|
||||
@change="unionChange"
|
||||
@open="setFilterOpened(true)"
|
||||
@close="setFilterOpened(false)">
|
||||
</van-dropdown-item>
|
||||
<van-dropdown-item
|
||||
v-model="pageForm.unitId"
|
||||
:options="unitList"
|
||||
@change="doSearch"
|
||||
@open="setFilterOpened(true)"
|
||||
@close="setFilterOpened(false)">
|
||||
</van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
|
||||
<table-list api="/platform/member/apply/mine/pageData" :page_form.sync="pageForm" ref="tableListRef" title="userName" @ready="doSearch">
|
||||
<main class="member-mine-content">
|
||||
<div class="member-mine-list">
|
||||
<div v-if="pageForm.totalCount === 0" class="member-mine-empty">
|
||||
<img src="/assets/mobile/img/home/v4/app-center-empty-v4.png" alt="暂无入会申请记录">
|
||||
<div class="member-mine-empty__title">暂无入会申请记录</div>
|
||||
<div class="member-mine-empty__hint">当前筛选条件下暂时没有入会申请</div>
|
||||
</div>
|
||||
<table-list api="/platform/member/apply/mine/pageData" :page_form.sync="pageForm" ref="tableListRef" title="userName" @loading-change="onListLoadingChange" @ready="onTableReady">
|
||||
<template #header="{index,row}">
|
||||
<div class="member-mine-card-header">
|
||||
<div class="member-mine-card-heading">
|
||||
<div class="member-mine-card-title">{{row.userName || '--'}}</div>
|
||||
<div class="member-mine-card-code">工号:{{row.loginName || '--'}}</div>
|
||||
</div>
|
||||
<enum-tag
|
||||
class="member-mine-card-status"
|
||||
v-if="row.instanceState"
|
||||
:value="row.instanceState"
|
||||
name="ProcessInstanceStateEnum"
|
||||
label_key="message"
|
||||
size="small">
|
||||
</enum-tag>
|
||||
<span v-else class="member-mine-card-status member-mine-card-status--plain">待提交</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="工号">{{row.loginName}}</table-column>
|
||||
<table-column label="所属工会">{{row.unionName}}</table-column>
|
||||
<table-column label="工作单位">{{row.unitName}}</table-column>
|
||||
<table-column label="填报时间">{{row.applyDateTime}}</table-column>
|
||||
<table-column label="当前节点">{{row.taskName}}</table-column>
|
||||
<table-column label="当前节点">{{row.taskName || '待提交'}}</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskKey === 'startTask' || !row.instanceId"
|
||||
@click="onEdit(row)">
|
||||
<i class="fa fa-edit"></i>
|
||||
<van-icon name="edit"></van-icon>
|
||||
<span>编辑</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-undo"></i>
|
||||
<van-icon name="revoke"></van-icon>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.taskKey === 'startTask' || !row.instanceId"
|
||||
@click="onDelete(row.id)">
|
||||
<i class="fa fa-trash"></i>
|
||||
<van-icon name="delete-o"></van-icon>
|
||||
<span>删除</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<info ref="infoRef"></info>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../common/info.js"){}#-->
|
||||
@@ -75,6 +395,13 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
unionList: [],
|
||||
unitList: [],
|
||||
pageLoading: true,
|
||||
filterOpened: false,
|
||||
filterReady: false,
|
||||
tableReady: false,
|
||||
initialSearchStarted: false,
|
||||
// 标识最近一次单位查询,避免快速切换分工会时旧请求覆盖新选项。
|
||||
unitRequestSequence: 0
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -83,10 +410,35 @@ layout("/layouts/platform_h5.html"){
|
||||
methods: {
|
||||
historyBack,
|
||||
|
||||
// 同步筛选弹层状态,用于切换下拉菜单圆角样式。
|
||||
setFilterOpened(opened) {
|
||||
this.$set(this, "filterOpened", opened)
|
||||
},
|
||||
|
||||
onView(row) {
|
||||
this.$refs.infoRef.onOpen(row)
|
||||
},
|
||||
|
||||
onListLoadingChange(state) {
|
||||
if (state.initial) {
|
||||
if (!state.loading && this.initialSearchStarted) {
|
||||
this.$set(this, "pageLoading", false)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onTableReady() {
|
||||
this.$set(this, "tableReady", true)
|
||||
this.tryInitialSearch()
|
||||
},
|
||||
|
||||
// 工会、单位筛选项与列表组件都完成初始化后,只触发一次首次查询。
|
||||
tryInitialSearch() {
|
||||
if (!this.filterReady || !this.tableReady || this.initialSearchStarted) return
|
||||
this.$set(this, "initialSearchStarted", true)
|
||||
this.doSearch()
|
||||
},
|
||||
|
||||
onEdit(row) {
|
||||
this.$pjaxReplace('/platform/member/apply/submit/h5?taskId=' + (row.startTaskId || '') + "&bizId=" + row.id)
|
||||
},
|
||||
@@ -140,47 +492,66 @@ layout("/layouts/platform_h5.html"){
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$refs.tableListRef.doSearch()
|
||||
// 下拉框先更新父页面筛选值,下一帧再查询,避免 TableList 将旧 unitId 回写覆盖当前选择。
|
||||
this.$nextTick(() => {
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
if (this.$refs.tableListRef) {
|
||||
this.$refs.tableListRef.doSearch()
|
||||
}
|
||||
})
|
||||
},
|
||||
unionChange() {
|
||||
// unionId 为本次下拉选择的分工会 ID;切换后只加载该分工会所属单位并刷新列表。
|
||||
unionChange(unionId) {
|
||||
this.$set(this.pageForm, "unionId", unionId)
|
||||
this.$set(this.pageForm, "unitId", null)
|
||||
this.flushUnits()
|
||||
this.doSearch()
|
||||
this.$set(this, "unitList", [{text: "全部单位", value: null}])
|
||||
this.flushUnits(unionId).then((applied) => {
|
||||
if (applied) this.doSearch()
|
||||
})
|
||||
},
|
||||
async initUnion() {
|
||||
initUnion() {
|
||||
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||
const unionId = hasAdmin ? null : this.$store.state.user.union.id
|
||||
this.unionList = await this.$businessTool.listUnion(unionId)
|
||||
this.unionList.forEach((v) => {
|
||||
v.text = v.name
|
||||
v.value = v.id
|
||||
return this.$businessTool.listUnion(unionId).then((data) => {
|
||||
const options = (data || []).map((v) => ({
|
||||
text: v.name,
|
||||
value: v.id
|
||||
}))
|
||||
if (hasAdmin) {
|
||||
options.unshift({text: "全部工会", value: null})
|
||||
}
|
||||
this.$set(this, "unionList", options)
|
||||
if (options.length > 0) {
|
||||
this.$set(this.pageForm, "unionId", options[0].value)
|
||||
}
|
||||
})
|
||||
if (hasAdmin) {
|
||||
this.unionList.unshift({ text: "全部工会", value: null })
|
||||
}
|
||||
if (this.unionList && this.unionList.length > 0) {
|
||||
this.$set(this.pageForm, "unionId", this.unionList[0].value)
|
||||
}
|
||||
},
|
||||
async flushUnits() {
|
||||
// selectedUnionId 为选中的分工会 ID;返回 true 表示本次单位查询结果已应用到页面。
|
||||
flushUnits(selectedUnionId) {
|
||||
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||
const unionId = hasAdmin ? this.pageForm.unionId : this.$store.state.user.union.id
|
||||
this.unitList = await this.$businessTool.listUnit(unionId)
|
||||
this.unitList.forEach((v) => {
|
||||
v.text = v.name
|
||||
v.value = v.id
|
||||
const unionId = hasAdmin ? selectedUnionId : this.$store.state.user.union.id
|
||||
const requestSequence = this.unitRequestSequence + 1
|
||||
this.$set(this, "unitRequestSequence", requestSequence)
|
||||
return this.$businessTool.listUnit(unionId).then((data) => {
|
||||
// 仅接收最后一次分工会切换的查询结果,防止异步返回顺序造成单位串联错误。
|
||||
if (requestSequence !== this.unitRequestSequence) return false
|
||||
const options = (data || []).map((v) => ({
|
||||
text: v.name,
|
||||
value: v.id
|
||||
}))
|
||||
options.unshift({text: "全部单位", value: null})
|
||||
this.$set(this, "unitList", options)
|
||||
this.$set(this.pageForm, "unitId", options[0].value)
|
||||
return true
|
||||
})
|
||||
this.unitList.unshift({ text: "全部单位", value: null })
|
||||
if (this.unitList && this.unitList.length > 0) {
|
||||
this.$set(this.pageForm, "unitId", this.unitList[0].value)
|
||||
}
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.initUnion()
|
||||
await this.flushUnits()
|
||||
created() {
|
||||
this.initUnion().then(() => this.flushUnits(this.pageForm.unionId)).finally(() => {
|
||||
this.$set(this, "filterReady", true)
|
||||
this.tryInitialSearch()
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
+364
-51
@@ -1,49 +1,326 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="入会校工会审核" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<van-sticky>
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
placeholder="请输入工号或者姓名进行查询"
|
||||
show-action
|
||||
:reverse-color="false"
|
||||
input-align="left"
|
||||
@search="doSearch">
|
||||
<template #action>
|
||||
<div @click="doSearch">搜索</div>
|
||||
</template>
|
||||
</van-search>
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<van-dropdown-item :options="unitList" @change="doSearch" v-model="pageForm.unitId"></van-dropdown-item>
|
||||
<van-dropdown-item :options="auditList" @change="doSearch" v-model="pageForm.audit"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
<style id="style-member-school-approval-h5">
|
||||
<!--#include("../../theme.css"){}#-->
|
||||
|
||||
<table-list api="/platform/member/apply/schoolUnionApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="userName" @ready="doSearch">
|
||||
body,
|
||||
.member-audit-page {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-audit-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.member-audit-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.member-audit-page .van-nav-bar__title {
|
||||
color: #172033;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-audit-page .van-nav-bar .van-icon,
|
||||
.member-audit-page .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.member-audit-sticky {
|
||||
padding: 22px 12px 1px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-audit-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.member-audit-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.member-audit-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-audit-search .van-field__control::placeholder {
|
||||
color: #a7b0bf;
|
||||
}
|
||||
|
||||
.member-audit-filter {
|
||||
margin: 0 0 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.member-audit-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-menu__bar,
|
||||
.member-audit-filter .van-dropdown-menu__item,
|
||||
.member-audit-filter .van-dropdown-menu__title {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-menu__bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-menu__title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-menu__title--active,
|
||||
.member-audit-filter .van-dropdown-item__option--active,
|
||||
.member-audit-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
}
|
||||
|
||||
.member-audit-filter .van-dropdown-item__option {
|
||||
display: flex;
|
||||
min-height: 48px;
|
||||
padding: 0 16px;
|
||||
align-items: center;
|
||||
color: #46566c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-audit-content {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.member-audit-list .table-list-container {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.member-audit-list .empty-state {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.member-audit-empty {
|
||||
display: flex;
|
||||
min-height: 280px;
|
||||
padding: 46px 18px 36px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.member-audit-empty img {
|
||||
display: block;
|
||||
width: 86%;
|
||||
max-width: 290px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.member-audit-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-audit-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-audit-card-header {
|
||||
display: flex;
|
||||
margin-bottom: 7px;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.member-audit-card-heading {
|
||||
min-width: 0;
|
||||
padding-right: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.member-audit-card-title {
|
||||
overflow: hidden;
|
||||
color: #253247;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-audit-card-code {
|
||||
margin-top: 1px;
|
||||
color: #9ba6b6;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-audit-status {
|
||||
display: inline-flex;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
.member-audit-status .van-tag {
|
||||
display: inline-flex;
|
||||
min-height: 24px;
|
||||
padding: 3px 9px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border: 0;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-audit-page .table-list-container .table-list-item .action-btn .van-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton {
|
||||
min-height: calc(100vh - 46px);
|
||||
padding: 22px 12px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton__filter,
|
||||
.member-audit-page-skeleton__card {
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .07);
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton__filter {
|
||||
min-height: 96px;
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton__card {
|
||||
min-height: 154px;
|
||||
}
|
||||
|
||||
.member-audit-page-skeleton .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
.member-audit-content,
|
||||
.member-audit-sticky {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<div class="member-h5-page member-audit-page">
|
||||
<van-nav-bar title="校工会审核" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<div class="member-audit-page-skeleton" v-if="pageLoading">
|
||||
<div class="member-audit-page-skeleton__filter"><van-skeleton title :row="2"></van-skeleton></div>
|
||||
<div class="member-audit-page-skeleton__cards">
|
||||
<div class="member-audit-page-skeleton__card" v-for="index in 3" :key="'school-page-skeleton-' + index">
|
||||
<van-skeleton title :row="4"></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="!pageLoading">
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="member-audit-sticky">
|
||||
<van-search v-model="pageForm.searchKeyword" class="member-audit-search"
|
||||
placeholder="请输入工号或姓名搜索" shape="round" clearable
|
||||
@search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="member-audit-filter" :class="{'is-open': filterOpened}"
|
||||
active-color="#1989fa" :close-on-click-outside="false"
|
||||
:close-on-click-overlay="false">
|
||||
<van-dropdown-item v-model="pageForm.unitId" :options="unitList" @change="doSearch"
|
||||
@open="setFilterOpened(true)" @close="setFilterOpened(false)"></van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.audit" :options="auditList" @change="doSearch"
|
||||
@open="setFilterOpened(true)" @close="setFilterOpened(false)"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
<main class="member-audit-content">
|
||||
<div class="member-audit-list">
|
||||
<div v-if="pageForm.totalCount === 0" class="member-audit-empty">
|
||||
<img src="/assets/mobile/img/home/v4/app-center-empty-v4.png" alt="暂无校工会审核数据">
|
||||
<div class="member-audit-empty__title">暂无审核数据</div>
|
||||
<div class="member-audit-empty__hint">当前筛选条件下没有需要办理的入会申请</div>
|
||||
</div>
|
||||
<table-list v-show="!initialLoading" api="/platform/member/apply/schoolUnionApproval/pageData" :page_form.sync="pageForm" ref="tableListRef" title="userName" :show_loading_overlay="false" @loading-change="onListLoadingChange" @ready="onReady">
|
||||
<template #header="{index,row}">
|
||||
<div class="member-audit-card-header">
|
||||
<div class="member-audit-card-heading">
|
||||
<div class="member-audit-card-title">{{row.userName || '--'}}</div>
|
||||
<div class="member-audit-card-code">工号:{{row.loginName || '--'}}</div>
|
||||
</div>
|
||||
<enum-tag class="member-audit-status" v-if="row.instanceState" :value="row.instanceState"
|
||||
name="ProcessInstanceStateEnum" label_key="message" size="small"></enum-tag>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="工号">{{row.loginName}}</table-column>
|
||||
<table-column label="所属工会">{{row.unionName}}</table-column>
|
||||
<table-column label="工作单位">{{row.unitName}}</table-column>
|
||||
<table-column label="填报时间">{{row.applyDateTime}}</table-column>
|
||||
<table-column label="当前节点">{{row.curTaskName}}</table-column>
|
||||
<table-column label="所属工会">{{row.unionName || '--'}}</table-column>
|
||||
<table-column label="工作单位">{{row.unitName || '--'}}</table-column>
|
||||
<table-column label="填报时间">{{row.applyDateTime || '--'}}</table-column>
|
||||
<table-column label="当前节点">{{row.curTaskName || '--'}}</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="onView(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
<div class="action-btn" v-if="row.taskState === 10" @click="onApproval(row)">
|
||||
<i class="fa fa-check"></i>
|
||||
<van-icon name="edit"></van-icon>
|
||||
<span>审核</span>
|
||||
</div>
|
||||
<div class="action-btn delete" v-if="row.canRevoke" @click="onRevoke(row)">
|
||||
<i class="fa fa-undo"></i>
|
||||
<van-icon name="revoke"></van-icon>
|
||||
<span>撤回</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<info ref="infoRef">
|
||||
<div v-if="showApprovalForm">
|
||||
@@ -60,13 +337,15 @@ layout("/layouts/platform_h5.html"){
|
||||
show-word-limit
|
||||
></van-field>
|
||||
</van-form>
|
||||
<div style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button type="primary" block @click="handleTaskAction(1)">同意</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(2)">拒绝</van-button>
|
||||
<van-button type="danger" block @click="handleTaskAction(6)">退回</van-button>
|
||||
<div class="member-approval-actions">
|
||||
<van-button class="member-agree-button" block :loading="formLoading" :disabled="formLoading" @click="handleTaskAction(1)">同意</van-button>
|
||||
<van-button type="danger" block :disabled="formLoading" @click="handleTaskAction(2)">拒绝</van-button>
|
||||
<van-button class="member-return-button" block :disabled="formLoading" @click="handleTaskAction(6)">退回</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</info>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../common/info.js"){}#-->
|
||||
@@ -83,6 +362,7 @@ layout("/layouts/platform_h5.html"){
|
||||
unitId: "",
|
||||
audit: false
|
||||
},
|
||||
unionList: [],
|
||||
unitList: [],
|
||||
auditList: [
|
||||
{ text: "已审核", value: true },
|
||||
@@ -91,7 +371,14 @@ layout("/layouts/platform_h5.html"){
|
||||
|
||||
// 审核相关
|
||||
formData: {},
|
||||
showApprovalForm: false
|
||||
showApprovalForm: false,
|
||||
initialLoading: true,
|
||||
formLoading: false,
|
||||
pageLoading: true,
|
||||
filterOpened: false,
|
||||
filterReady: false,
|
||||
tableReady: false,
|
||||
initialSearchStarted: false
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -100,18 +387,47 @@ layout("/layouts/platform_h5.html"){
|
||||
methods: {
|
||||
historyBack,
|
||||
|
||||
// 同步筛选弹层展开状态,用于保持与提案预审核一致的筛选栏圆角。
|
||||
setFilterOpened(opened) {
|
||||
this.$set(this, "filterOpened", opened)
|
||||
},
|
||||
|
||||
onReady() {
|
||||
this.$set(this, "tableReady", true)
|
||||
this.tryInitialSearch()
|
||||
},
|
||||
|
||||
// 工会、单位筛选项与列表组件都完成初始化后,只触发一次首次查询。
|
||||
tryInitialSearch() {
|
||||
if (!this.filterReady || !this.tableReady || this.initialSearchStarted) return
|
||||
this.$set(this, "initialSearchStarted", true)
|
||||
this.doSearch()
|
||||
},
|
||||
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
|
||||
onListLoadingChange(state) {
|
||||
if (state.initial) {
|
||||
this.$set(this, "initialLoading", state.loading)
|
||||
if (!state.loading && this.initialSearchStarted) {
|
||||
this.$set(this, "pageLoading", false)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
unionChange() {
|
||||
this.$set(this.pageForm, "unitId", null)
|
||||
this.flushUnits().then(() => {
|
||||
this.doSearch()
|
||||
})
|
||||
},
|
||||
|
||||
// 查看详情
|
||||
onView(row) {
|
||||
this.showApprovalForm = false
|
||||
@@ -127,18 +443,13 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
|
||||
async handleTaskAction(val) {
|
||||
await this.$refs.formRef.validate();
|
||||
this.$dialog.confirm({
|
||||
handleTaskAction(val) {
|
||||
if (this.formLoading) return
|
||||
this.$refs.formRef.validate().then(() => this.$dialog.confirm({
|
||||
title: "提示",
|
||||
message: "您确定要提交吗?"
|
||||
}).then(() => {
|
||||
const loading = this.$toast.loading({
|
||||
message: "加载中...",
|
||||
forbidClick: true,
|
||||
overlay: true,
|
||||
duration: 0
|
||||
})
|
||||
})).then(() => {
|
||||
this.formLoading = true
|
||||
this.$axios.post("/flow/common/executeTask", {
|
||||
data: JSON.stringify({
|
||||
...this.formData,
|
||||
@@ -151,7 +462,7 @@ layout("/layouts/platform_h5.html"){
|
||||
this.doSearch()
|
||||
}
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
this.formLoading = false
|
||||
})
|
||||
})
|
||||
},
|
||||
@@ -182,7 +493,7 @@ layout("/layouts/platform_h5.html"){
|
||||
initUnion() {
|
||||
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||
const unionId = hasAdmin ? null : this.$store.state.user.union.id
|
||||
this.$businessTool.listUnion(unionId).then((data) => {
|
||||
return this.$businessTool.listUnion(unionId).then((data) => {
|
||||
this.unionList = data
|
||||
this.unionList.forEach((v) => {
|
||||
v.text = v.name
|
||||
@@ -199,7 +510,7 @@ layout("/layouts/platform_h5.html"){
|
||||
flushUnits() {
|
||||
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||
const unionId = hasAdmin ? this.pageForm.unionId : this.$store.state.user.union.id
|
||||
this.$businessTool.listUnit(unionId).then((data) => {
|
||||
return this.$businessTool.listUnit(unionId).then((data) => {
|
||||
this.unitList = data
|
||||
this.unitList.forEach((v) => {
|
||||
v.text = v.name
|
||||
@@ -212,9 +523,11 @@ layout("/layouts/platform_h5.html"){
|
||||
})
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
await this.initUnion()
|
||||
await this.flushUnits()
|
||||
created() {
|
||||
this.initUnion().then(() => this.flushUnits()).finally(() => {
|
||||
this.$set(this, "filterReady", true)
|
||||
this.tryInitialSearch()
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
+246
-107
@@ -1,7 +1,9 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
<style id="style-member-apply-submit-h5">
|
||||
<!--#include("../../theme.css"){}#-->
|
||||
|
||||
.up_down > .van-cell {
|
||||
flex-flow: column;
|
||||
}
|
||||
@@ -10,14 +12,79 @@ layout("/layouts/platform_h5.html"){
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.van-cell, .van-picker button, .submit .van-button--normal {
|
||||
font-size: 16px;
|
||||
.member-family-heading,
|
||||
.member-family-card__heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.member-family-card {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #edf1f6;
|
||||
border-radius: 10px;
|
||||
background: #f8fbff;
|
||||
}
|
||||
|
||||
.member-family-card__heading {
|
||||
color: #42546c;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-family-empty {
|
||||
padding: 28px 0;
|
||||
color: #9aa7b8;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.member-family-empty__text {
|
||||
margin-bottom: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.member-voluntary {
|
||||
padding: 12px 14px;
|
||||
color: #596779;
|
||||
font-size: 13px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.member-voluntary__paragraph + .member-voluntary__paragraph {
|
||||
margin-top: 6px;
|
||||
}
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="入会申请" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<div class="member-h5-page" :class="{'has-fixed-actions': showActionButtons}">
|
||||
<van-nav-bar title="入会申请" left-text="返回" left-arrow @click-left="handlePageBack" placeholder fixed></van-nav-bar>
|
||||
|
||||
<van-form ref="formRef" class="form-container" :show-error-message="false">
|
||||
<div class="member-page-skeleton" v-if="pageLoading">
|
||||
<div class="member-page-skeleton__hero"><van-skeleton title :row="1"></van-skeleton></div>
|
||||
<div class="member-page-skeleton__cards member-list-skeleton">
|
||||
<div class="member-form-skeleton__card" v-for="index in 3" :key="'member-form-skeleton-' + index">
|
||||
<van-skeleton title :row="5"></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<header class="member-hero" v-show="!pageLoading">
|
||||
<div class="member-hero__content">
|
||||
<div class="member-hero__title">会员入会</div>
|
||||
<div class="member-hero__subtitle">凝聚职工 · 温暖同行</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="member-page-main" v-show="!pageLoading">
|
||||
<div class="member-form-intro">
|
||||
<van-icon name="info-o"></van-icon>
|
||||
<div>
|
||||
<div class="member-form-intro__title">入会信息确认</div>
|
||||
<div class="member-form-intro__text">请核对个人信息并完整填写申请资料,带星号的内容为必填项。</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<van-form ref="formRef" class="form-container member-application-form" :show-error-message="false">
|
||||
<van-cell-group title="基础信息" class="form-section">
|
||||
<van-field v-model="formData.loginname" label="工号" readonly></van-field>
|
||||
<van-field v-model="formData.username" label="姓名" readonly></van-field>
|
||||
@@ -28,14 +95,14 @@ layout("/layouts/platform_h5.html"){
|
||||
label="民族"
|
||||
readonly
|
||||
placeholder="请点击选择民族"
|
||||
@click="showNationPicker = true"
|
||||
@click="setLayerVisible('showNationPicker', true)"
|
||||
clickable
|
||||
></van-field>
|
||||
<van-popup position="bottom" round v-model:show="showNationPicker">
|
||||
<van-popup position="bottom" round v-model="showNationPicker" :close-on-click-overlay="false">
|
||||
<van-picker show-toolbar
|
||||
:columns="nationColumns"
|
||||
@cancel="showNationPicker = false"
|
||||
@confirm="(v)=>{formData.nation = v;showNationPicker = false}"
|
||||
@cancel="setLayerVisible('showNationPicker', false)"
|
||||
@confirm="onNationConfirm"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
<van-field
|
||||
@@ -43,16 +110,16 @@ layout("/layouts/platform_h5.html"){
|
||||
label="出生年月"
|
||||
is-link
|
||||
readonly
|
||||
@click="showDatePicker = true"
|
||||
@click="setLayerVisible('showDatePicker', true)"
|
||||
:rules="[{ required: true, message: '请填写出生年月' }]"
|
||||
></van-field>
|
||||
<van-popup v-model="showDatePicker" position="bottom">
|
||||
<van-popup v-model="showDatePicker" position="bottom" :close-on-click-overlay="false">
|
||||
<van-datetime-picker
|
||||
type="date"
|
||||
:min-date="new Date(1900, 0, 1)"
|
||||
:max-date="new Date()"
|
||||
@confirm="onDateConfirm"
|
||||
@cancel="showDatePicker=false"
|
||||
@cancel="setLayerVisible('showDatePicker', false)"
|
||||
></van-datetime-picker>
|
||||
</van-popup>
|
||||
<van-field
|
||||
@@ -62,14 +129,14 @@ layout("/layouts/platform_h5.html"){
|
||||
readonly
|
||||
is-link
|
||||
placeholder="请选择政治面貌"
|
||||
@click="showPoliticalPicker = true"
|
||||
@click="setLayerVisible('showPoliticalPicker', true)"
|
||||
clickable
|
||||
></van-field>
|
||||
<van-popup position="bottom" round v-model:show="showPoliticalPicker">
|
||||
<van-popup position="bottom" round v-model="showPoliticalPicker" :close-on-click-overlay="false">
|
||||
<van-picker show-toolbar
|
||||
:columns="politicalColumns"
|
||||
@cancel="showPoliticalPicker = false"
|
||||
@confirm="(v)=>{formData.political = v;showPoliticalPicker = false}"
|
||||
@cancel="setLayerVisible('showPoliticalPicker', false)"
|
||||
@confirm="onPoliticalConfirm"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
<van-field
|
||||
@@ -79,14 +146,14 @@ layout("/layouts/platform_h5.html"){
|
||||
readonly
|
||||
is-link
|
||||
placeholder="请选择学历"
|
||||
@click="showEducationPicker = true"
|
||||
@click="setLayerVisible('showEducationPicker', true)"
|
||||
clickable
|
||||
></van-field>
|
||||
<van-popup position="bottom" round v-model:show="showEducationPicker">
|
||||
<van-popup position="bottom" round v-model="showEducationPicker" :close-on-click-overlay="false">
|
||||
<van-picker show-toolbar
|
||||
:columns="educationColumns"
|
||||
@cancel="showEducationPicker = false"
|
||||
@confirm="(v)=>{formData.education = v;showEducationPicker = false}"
|
||||
@cancel="setLayerVisible('showEducationPicker', false)"
|
||||
@confirm="onEducationConfirm"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
<van-field
|
||||
@@ -96,14 +163,14 @@ layout("/layouts/platform_h5.html"){
|
||||
readonly
|
||||
is-link
|
||||
placeholder="请选择学位"
|
||||
@click="showAcademicDegreePicker = true"
|
||||
@click="setLayerVisible('showAcademicDegreePicker', true)"
|
||||
clickable
|
||||
></van-field>
|
||||
<van-popup position="bottom" round v-model:show="showAcademicDegreePicker">
|
||||
<van-popup position="bottom" round v-model="showAcademicDegreePicker" :close-on-click-overlay="false">
|
||||
<van-picker show-toolbar
|
||||
:columns="academicDegreeColumns"
|
||||
@cancel="showAcademicDegreePicker = false"
|
||||
@confirm="(v)=>{formData.academicDegree = v;showAcademicDegreePicker = false}"
|
||||
@cancel="setLayerVisible('showAcademicDegreePicker', false)"
|
||||
@confirm="onAcademicDegreeConfirm"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
<van-field
|
||||
@@ -154,14 +221,14 @@ layout("/layouts/platform_h5.html"){
|
||||
readonly
|
||||
is-link
|
||||
placeholder="请选择婚姻状况"
|
||||
@click="showMarriagePicker = true"
|
||||
@click="setLayerVisible('showMarriagePicker', true)"
|
||||
clickable
|
||||
></van-field>
|
||||
<van-popup position="bottom" round v-model:show="showMarriagePicker">
|
||||
<van-popup position="bottom" round v-model="showMarriagePicker" :close-on-click-overlay="false">
|
||||
<van-picker show-toolbar
|
||||
:columns="marriageColumns"
|
||||
@cancel="showMarriagePicker = false"
|
||||
@confirm="(v)=>{formData.marriage = v;showMarriagePicker = false}"
|
||||
@cancel="setLayerVisible('showMarriagePicker', false)"
|
||||
@confirm="onMarriageConfirm"
|
||||
></van-picker>
|
||||
</van-popup>
|
||||
|
||||
@@ -215,25 +282,21 @@ layout("/layouts/platform_h5.html"){
|
||||
|
||||
<van-cell-group title="家庭信息" class="form-section up_down">
|
||||
<div class="van-cell">
|
||||
<div style="display: flex;justify-content: space-between">
|
||||
<div style="display: flex;">
|
||||
<div style="width: 100%">
|
||||
<span>家庭主要成员及联系方式</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="member-family-heading">
|
||||
<span>家庭主要成员及联系方式</span>
|
||||
<van-button v-if="formData.families && formData.families.length>0 && formData.families.length<5"
|
||||
style="width: 40px"
|
||||
icon="plus" type="primary" round size="mini"
|
||||
@click="formData.families.push({})"
|
||||
@click="addFamilyMember"
|
||||
native-type="button"></van-button>
|
||||
</div>
|
||||
<template v-if="formData.families && formData.families.length>0">
|
||||
<div v-for="o,i in formData.families" class="mt5">
|
||||
<div style="font-weight: 700;display: flex;justify-content: space-between">
|
||||
<div v-for="(o,i) in formData.families" :key="'family-' + i" class="member-family-card">
|
||||
<div class="member-family-card__heading">
|
||||
<span>成员{{toChinesNum(i+1)}}</span>
|
||||
<van-button style="width: 40px"
|
||||
icon="cross" type="danger" round size="mini"
|
||||
@click="formData.families.splice(i,1)"
|
||||
@click="removeFamilyMember(i)"
|
||||
native-type="button"></van-button>
|
||||
</div>
|
||||
<van-field label="关系" v-model="o.relation" placeholder="请填写与本人关系"
|
||||
@@ -247,10 +310,11 @@ layout("/layouts/platform_h5.html"){
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div style="padding: 50px;text-align: center">
|
||||
<div class="member-family-empty">
|
||||
<div class="member-family-empty__text">暂未填写家庭成员</div>
|
||||
<van-button style="width: 50px"
|
||||
icon="plus" type="primary" round size="mini"
|
||||
@click="formData.families.push({})"
|
||||
@click="addFamilyMember"
|
||||
native-type="button"></van-button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -266,26 +330,28 @@ layout("/layouts/platform_h5.html"){
|
||||
</van-cell-group>
|
||||
|
||||
<van-cell-group title="入会意愿" class="form-section">
|
||||
<van-checkbox style="font-size: 17px;padding: 12px" icon-size="24px"
|
||||
<van-checkbox class="member-voluntary" icon-size="22px"
|
||||
v-model="formData.isVoluntary" shape="square">
|
||||
<div style="text-indent: 2.1rem">
|
||||
<div class="member-voluntary__paragraph">
|
||||
<span :style="'color:' + (formData.isVoluntary ? '#1989fa' : '#F56C6C') ">
|
||||
我自愿申请加入学校工会,并委托学校按规定代为扣缴工会会员会费。
|
||||
</span>
|
||||
</div>
|
||||
<div style="text-indent: 2.1rem">
|
||||
<div class="member-voluntary__paragraph">
|
||||
<span :style="'color:' + (formData.isVoluntary ? '#1989fa' : '#F56C6C') ">
|
||||
我将严格遵守工会章程,认真执行工会决议,积极参与工会活动,主动融入“学校健康幸福家”建设,为营造温暖、和谐、奋进的校园氛围贡献力量,以实际行动助力学校各项事业发展。
|
||||
</span>
|
||||
</div>
|
||||
</van-checkbox>
|
||||
</van-cell-group>
|
||||
<div v-if="showActionButtons" style="display: flex; justify-content: space-between; column-gap: 10px; padding: 10px">
|
||||
<van-button block type="primary" @click.submit="onSave">保存</van-button>
|
||||
<van-button v-if="!taskId" block type="primary" @click.submit="onSubmit">提交</van-button>
|
||||
<van-button v-else block type="primary" @click.submit="onFinishTask">提交</van-button>
|
||||
<div v-if="showActionButtons" class="member-form-actions">
|
||||
<van-button block plain class="member-save-button" :loading="formLoading && loadingAction === 'save'" :disabled="formLoading" @click.submit="onSave">保存草稿</van-button>
|
||||
<van-button v-if="!taskId" block type="primary" class="member-submit-button" :loading="formLoading && loadingAction === 'submit'" :disabled="formLoading" @click.submit="onSubmit">提交申请</van-button>
|
||||
<van-button v-else block type="primary" class="member-submit-button" :loading="formLoading && loadingAction === 'submitAgain'" :disabled="formLoading" @click.submit="onFinishTask">重新提交</van-button>
|
||||
</div>
|
||||
</van-form>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
new Vue({
|
||||
@@ -298,6 +364,10 @@ layout("/layouts/platform_h5.html"){
|
||||
taskId: GetQueryString("taskId"),
|
||||
// 当前登录人已是会员时,不显示保存和提交按钮。
|
||||
showActionButtons: true,
|
||||
pageLoading: true,
|
||||
formLoading: false,
|
||||
loadingAction: "",
|
||||
historyLayerPageKey: "member-apply-submit",
|
||||
formData: {
|
||||
families: []
|
||||
},
|
||||
@@ -319,21 +389,90 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
historyBack,
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
historyBack()
|
||||
},
|
||||
|
||||
/**
|
||||
* 同步入会表单选择器与浏览器历史。
|
||||
* stateName 为选择器状态字段,visible 为目标显示状态;方法无返回值。
|
||||
*/
|
||||
setLayerVisible(stateName, visible) {
|
||||
const layerName = {
|
||||
showNationPicker: "nation-picker",
|
||||
showDatePicker: "birthday-picker",
|
||||
showPoliticalPicker: "political-picker",
|
||||
showEducationPicker: "education-picker",
|
||||
showAcademicDegreePicker: "degree-picker",
|
||||
showMarriagePicker: "marriage-picker"
|
||||
}[stateName]
|
||||
if (visible) {
|
||||
window.h5HistoryLayerManager.open(layerName)
|
||||
return
|
||||
}
|
||||
window.h5HistoryLayerManager.close(layerName)
|
||||
},
|
||||
|
||||
registerHistoryLayers() {
|
||||
// 六个选择器共用页面级历史栈,手机返回键只关闭当前最上层选择器。
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.$set(this, "showNationPicker", stack.includes("nation-picker"))
|
||||
this.$set(this, "showDatePicker", stack.includes("birthday-picker"))
|
||||
this.$set(this, "showPoliticalPicker", stack.includes("political-picker"))
|
||||
this.$set(this, "showEducationPicker", stack.includes("education-picker"))
|
||||
this.$set(this, "showAcademicDegreePicker", stack.includes("degree-picker"))
|
||||
this.$set(this, "showMarriagePicker", stack.includes("marriage-picker"))
|
||||
})
|
||||
},
|
||||
|
||||
onNationConfirm(value) {
|
||||
this.$set(this.formData, "nation", value)
|
||||
this.setLayerVisible("showNationPicker", false)
|
||||
},
|
||||
|
||||
onPoliticalConfirm(value) {
|
||||
this.$set(this.formData, "political", value)
|
||||
this.setLayerVisible("showPoliticalPicker", false)
|
||||
},
|
||||
|
||||
onEducationConfirm(value) {
|
||||
this.$set(this.formData, "education", value)
|
||||
this.setLayerVisible("showEducationPicker", false)
|
||||
},
|
||||
|
||||
onAcademicDegreeConfirm(value) {
|
||||
this.$set(this.formData, "academicDegree", value)
|
||||
this.setLayerVisible("showAcademicDegreePicker", false)
|
||||
},
|
||||
|
||||
onMarriageConfirm(value) {
|
||||
this.$set(this.formData, "marriage", value)
|
||||
this.setLayerVisible("showMarriagePicker", false)
|
||||
},
|
||||
|
||||
addFamilyMember() {
|
||||
const nextIndex = this.formData.families.length
|
||||
this.$set(this.formData.families, nextIndex, {})
|
||||
},
|
||||
|
||||
removeFamilyMember(index) {
|
||||
this.formData.families.splice(index, 1)
|
||||
},
|
||||
|
||||
onSave() {
|
||||
if (this.formLoading) return
|
||||
this.$dialog.confirm({
|
||||
title: "提示",
|
||||
message: "您确定要保存吗?",
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消"
|
||||
}).then(() => {
|
||||
const loading = this.$toast.loading({
|
||||
message: "加载中...",
|
||||
forbidClick: true,
|
||||
overlay: true,
|
||||
duration: 0
|
||||
})
|
||||
this.formLoading = true
|
||||
this.loadingAction = "save"
|
||||
this.$axios.post("/platform/member/apply/submit/save", { data: JSON.stringify(this.formData) }).then(res => {
|
||||
if (res.code === 0) {
|
||||
this.$toast.success(res.msg)
|
||||
@@ -343,12 +482,14 @@ layout("/layouts/platform_h5.html"){
|
||||
console.log(res.msg)
|
||||
}
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
this.formLoading = false
|
||||
this.loadingAction = ""
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onSubmit() {
|
||||
if (this.formLoading) return
|
||||
this.$refs.formRef.validate().then(() => {
|
||||
if (!this.formData.personalData) {
|
||||
this.$toast.fail("请填写个人学习及工作经历")
|
||||
@@ -362,12 +503,8 @@ layout("/layouts/platform_h5.html"){
|
||||
title: "提示",
|
||||
message: "您确定要提交吗?"
|
||||
}).then(() => {
|
||||
const loading = this.$toast.loading({
|
||||
message: "加载中...",
|
||||
forbidClick: true,
|
||||
overlay: true,
|
||||
duration: 0
|
||||
})
|
||||
this.formLoading = true
|
||||
this.loadingAction = "submit"
|
||||
this.$axios.post("/platform/member/apply/submit/submit", {
|
||||
data: JSON.stringify(this.formData)
|
||||
}).then(res => {
|
||||
@@ -379,13 +516,15 @@ layout("/layouts/platform_h5.html"){
|
||||
console.log(res.msg)
|
||||
}
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
this.formLoading = false
|
||||
this.loadingAction = ""
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onFinishTask() {
|
||||
if (this.formLoading) return
|
||||
this.$refs.formRef.validate().then(() => {
|
||||
if (!this.formData.personalData) {
|
||||
this.$toast.fail("请填写个人学习及工作经历")
|
||||
@@ -399,12 +538,8 @@ layout("/layouts/platform_h5.html"){
|
||||
title: "提示",
|
||||
message: "您确定要提交吗?"
|
||||
}).then(() => {
|
||||
const loading = this.$toast.loading({
|
||||
message: "加载中...",
|
||||
forbidClick: true,
|
||||
overlay: true,
|
||||
duration: 0
|
||||
})
|
||||
this.formLoading = true
|
||||
this.loadingAction = "submitAgain"
|
||||
this.$axios.post("/platform/member/apply/submit/submitAgain", {
|
||||
data: JSON.stringify(this.formData),
|
||||
taskId: this.taskId
|
||||
@@ -417,39 +552,35 @@ layout("/layouts/platform_h5.html"){
|
||||
console.log(res.msg)
|
||||
}
|
||||
}).finally(() => {
|
||||
loading.close()
|
||||
this.formLoading = false
|
||||
this.loadingAction = ""
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
onDateConfirm(value) {
|
||||
this.formData.birthday = value
|
||||
this.showDatePicker = false
|
||||
this.$set(this.formData, "birthday", value)
|
||||
this.setLayerVisible("showDatePicker", false)
|
||||
},
|
||||
|
||||
async init() {
|
||||
let user
|
||||
const resp = await $.post("/platform/member/apply/submit/getSelfUserInfo")
|
||||
if (resp.code === 0) {
|
||||
if (!resp.data) {
|
||||
user = this.$store.state.user
|
||||
} else {
|
||||
user = resp.data
|
||||
}
|
||||
} else {
|
||||
user = this.$store.state.user
|
||||
}
|
||||
// 页面按钮是否展示,以当前登录人的会员状态为准。
|
||||
this.showActionButtons = !(user && user.member)
|
||||
init() {
|
||||
// 无参数获取当前登录人资料;有 id 时改查已有申请,接口均返回对应的用户/申请对象。
|
||||
return this.$axios.post("/platform/member/apply/submit/getSelfUserInfo", {}, {h5SkeletonLoading: true})
|
||||
.then((resp) => {
|
||||
const user = resp.code === 0 && resp.data ? resp.data : this.$store.state.user
|
||||
// 页面按钮是否展示,以当前登录人的会员状态为准。
|
||||
this.showActionButtons = !(user && user.member)
|
||||
|
||||
if (this.id) {
|
||||
return this.$axios.post("/platform/member/apply/submit/findApplyById", { id: this.id }, {h5SkeletonLoading: true})
|
||||
.then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.$set(this, "formData", res.data)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (this.id) {
|
||||
const res = await this.$axios.post("/platform/member/apply/submit/findApplyById", { id: this.id })
|
||||
debugger
|
||||
if (res.code === 0) {
|
||||
this.formData = res.data
|
||||
}
|
||||
} else {
|
||||
const {
|
||||
id,
|
||||
username,
|
||||
@@ -519,7 +650,7 @@ layout("/layouts/platform_h5.html"){
|
||||
this.$set(this.formData, "campus", "")
|
||||
this.$set(this.formData, "campusName", "")
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
toChinesNum(num) {
|
||||
let changeNum = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"]
|
||||
@@ -545,19 +676,20 @@ layout("/layouts/platform_h5.html"){
|
||||
this.$set(this.formData, "campus", o.value) // 字典值
|
||||
this.showCampusPicker = false
|
||||
},
|
||||
async initDictOptions() {
|
||||
// 初始化校区字典数据
|
||||
const campusData = await this.$businessTool.getDictOptions("USER_CAMPUS")
|
||||
this.campusColumns = campusData.map(item => {
|
||||
return { value: item.code, text: item.name }
|
||||
})
|
||||
// 初始化完成后,如果已经有用户数据,更新校区显示名称
|
||||
if (this.formData.campus && this.campusColumns.length > 0) {
|
||||
const campusItem = this.campusColumns.find(item => item.value === this.formData.campus)
|
||||
if (campusItem) {
|
||||
this.$set(this.formData, "campusName", campusItem.text)
|
||||
}
|
||||
}
|
||||
initDictOptions() {
|
||||
// USER_CAMPUS 返回校区字典数组;完成后同步已有表单的校区显示名称。
|
||||
return this.$businessTool.getDictOptions("USER_CAMPUS")
|
||||
.then((campusData) => {
|
||||
this.campusColumns = campusData.map((item) => {
|
||||
return { value: item.code, text: item.name }
|
||||
})
|
||||
if (this.formData.campus && this.campusColumns.length > 0) {
|
||||
const campusItem = this.campusColumns.find((item) => item.value === this.formData.campus)
|
||||
if (campusItem) {
|
||||
this.$set(this.formData, "campusName", campusItem.text)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -594,8 +726,15 @@ layout("/layouts/platform_h5.html"){
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.registerHistoryLayers()
|
||||
this.initDictOptions()
|
||||
this.init()
|
||||
.then(() => this.init())
|
||||
.finally(() => {
|
||||
this.pageLoading = false
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
+22
-5
@@ -1,5 +1,12 @@
|
||||
const MOBILE_MEMBER_INFO = {
|
||||
template: /*language=HTML*/ `
|
||||
<div class="member-info-scroll">
|
||||
<div class="member-list-skeleton" v-if="detailLoading">
|
||||
<div class="member-list-skeleton__card" v-for="index in 3" :key="'member-profile-skeleton-' + index">
|
||||
<van-skeleton title :row="5"></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div v-if="profileMode" class="mine-profile-details">
|
||||
<section class="mine-detail-card">
|
||||
<h2>基本信息</h2>
|
||||
@@ -24,7 +31,9 @@
|
||||
</section>
|
||||
</div>
|
||||
<div v-else class="detail-container">
|
||||
<van-cell-group title="基本信息">
|
||||
<section class="member-detail-card">
|
||||
<div class="member-detail-card__title">会员信息</div>
|
||||
<van-cell-group :border="false">
|
||||
<van-cell title="工号">{{ viewData.loginname }}</van-cell>
|
||||
<van-cell title="姓名">{{ viewData.username }}</van-cell>
|
||||
<van-cell title="性别">{{ viewData.sex }}</van-cell>
|
||||
@@ -81,6 +90,9 @@
|
||||
</van-cell>
|
||||
</template>
|
||||
</van-cell-group>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
`,
|
||||
props: {
|
||||
@@ -89,12 +101,13 @@
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
viewData: {}
|
||||
viewData: {},
|
||||
detailLoading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
userId: {
|
||||
handler: function () {
|
||||
handler() {
|
||||
this.findUserInfoByUserId()
|
||||
},
|
||||
immediate: true
|
||||
@@ -113,14 +126,18 @@
|
||||
}
|
||||
return mobile.replace(/^(\d{3})\d+(\d{4})$/, "$1****$2")
|
||||
},
|
||||
// userId 为系统用户主键;接口返回会员档案详情对象,加载期间显示档案骨架屏。
|
||||
findUserInfoByUserId() {
|
||||
if (!this.userId) {
|
||||
return
|
||||
}
|
||||
this.$axios.post("/platform/member/apply/common/findOne", { id: this.userId }).then((res) => {
|
||||
this.detailLoading = true
|
||||
this.$axios.post("/platform/member/apply/common/findOne", { id: this.userId }, {h5SkeletonLoading: true}).then((res) => {
|
||||
if (res.code === 0) {
|
||||
this.viewData = res.data
|
||||
this.$set(this, "viewData", res.data)
|
||||
}
|
||||
}).finally(() => {
|
||||
this.detailLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+315
-505
@@ -2,536 +2,346 @@
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style>
|
||||
.top-col {
|
||||
background-color: white;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
width: calc((100% - 5px) / 2);
|
||||
}
|
||||
|
||||
.top-col:not(:last-child),
|
||||
.center-col:not(:last-child) {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.col-title {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.top-col-member-number {
|
||||
font-size: 30px;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
}
|
||||
|
||||
.top-col-chart {
|
||||
height: 80px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.center-col {
|
||||
background-color: white;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
/*width: calc((100% - (20px * 1)) / 2);*/
|
||||
}
|
||||
|
||||
.idx {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: rgba(0, 0, 0, 0.85);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background-color: #f0f0f0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.idx-rank {
|
||||
color: white !important;
|
||||
background-color: #314659 !important;
|
||||
}
|
||||
|
||||
.el-table__body-wrapper::-webkit-scrollbar {
|
||||
display: none; /* Chrome Safari */
|
||||
}
|
||||
|
||||
.el-table__body-wrapper {
|
||||
scrollbar-width: none; /* firefox */
|
||||
-ms-overflow-style: none; /* IE 10+ */
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.data-box{
|
||||
text-align: center;
|
||||
font-size:13px;
|
||||
margin:12px 0;
|
||||
}
|
||||
.th-row,.td-row{
|
||||
display:flex;
|
||||
height:30px;
|
||||
line-height:30px;
|
||||
padding:0 12px;
|
||||
}
|
||||
.th-row{background:#f8f8f8;}
|
||||
|
||||
/* 关键:比例 + 最小宽度0 */
|
||||
.col-index{flex:0 0 60px;} /* 序号固定60 */
|
||||
.col-name{flex:1 1 120px;min-width:0;} /* 名称占剩余,最小120 */
|
||||
.col-num{flex:0 0 80px;text-align:right;} /* 人数固定80 */
|
||||
|
||||
.common-ellipsis{
|
||||
overflow:hidden;
|
||||
white-space:nowrap;
|
||||
text-overflow:ellipsis;
|
||||
body { background: #f3f7fd; }
|
||||
.member-board-page { min-height: 100vh; padding-bottom: calc(22px + env(safe-area-inset-bottom)); box-sizing: border-box; color: #263548; background: #f3f7fd; }
|
||||
.member-board-page .van-nav-bar { background: #fff; }
|
||||
.member-board-page .van-nav-bar__title { color: #1f2937; font-size: 16px; font-weight: 600; }
|
||||
.member-board-page .van-nav-bar .van-icon, .member-board-page .van-nav-bar__text { color: #1989fa; }
|
||||
.member-board-main { padding: 12px; box-sizing: border-box; }
|
||||
.member-board-card { overflow: hidden; border: 1px solid #e8eef6; border-radius: 12px; background: #fff; box-shadow: 0 7px 20px rgba(55, 85, 126, .08); }
|
||||
.member-board-section { margin-top: 10px; }
|
||||
.member-board-card__title { color: #2c3b50; font-size: 14px; line-height: 21px; font-weight: 600; }
|
||||
.member-board-summary { display: flex; min-height: 132px; padding: 16px; align-items: stretch; color: #fff; border: 0; background: #247fe8; box-sizing: border-box; box-shadow: 0 9px 22px rgba(36, 127, 232, .22); }
|
||||
.member-board-summary__number { display: flex; width: 42%; padding-right: 13px; justify-content: center; flex-direction: column; border-right: 1px solid rgba(255, 255, 255, .26); box-sizing: border-box; }
|
||||
.member-board-summary__label, .member-board-summary__trend-title { color: rgba(255, 255, 255, .88); font-size: 12px; line-height: 18px; }
|
||||
.member-board-summary__value { margin-top: 3px; color: #fff; font-size: 30px; line-height: 40px; font-weight: 700; letter-spacing: .5px; white-space: nowrap; }
|
||||
.member-board-summary__unit { margin-left: 3px; font-size: 13px; font-weight: 500; }
|
||||
.member-board-summary__ratio { display: flex; margin-top: 6px; align-items: center; color: rgba(255, 255, 255, .9); font-size: 11px; line-height: 18px; white-space: nowrap; }
|
||||
.member-board-summary__ratio .van-icon { margin-left: 5px; color: #7ee2a8; font-size: 12px; }
|
||||
.member-board-summary__ratio.is-down .van-icon { color: #ffb6b6; transform: rotate(180deg); }
|
||||
.member-board-summary__trend { min-width: 0; padding-left: 14px; flex: 1; box-sizing: border-box; }
|
||||
.member-board-summary__chart { width: 100%; height: 86px; margin-top: 1px; }
|
||||
.member-board-grid { display: grid; margin-top: 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
|
||||
.member-board-mini-card { min-width: 0; height: 158px; padding: 13px 12px 10px; box-sizing: border-box; }
|
||||
.member-board-mini-card__content { position: relative; height: 116px; }
|
||||
.member-board-mini-chart { width: 100%; height: 116px; }
|
||||
.member-board-ring-value { position: absolute; top: 50%; left: 50%; z-index: 2; color: #263548; font-size: 17px; font-weight: 600; transform: translate(-50%, -50%); pointer-events: none; }
|
||||
.member-board-sex-layout { display: flex; height: 116px; align-items: center; }
|
||||
.member-board-sex-chart { width: 58%; height: 112px; flex: none; }
|
||||
.member-board-sex-legend { min-width: 0; flex: 1; }
|
||||
.member-board-sex-legend__item { display: flex; margin: 8px 0; align-items: center; color: #56657a; font-size: 11px; line-height: 18px; }
|
||||
.member-board-sex-legend__dot { width: 7px; height: 7px; margin-right: 6px; flex: none; border-radius: 50%; background: #409eff; }
|
||||
.member-board-sex-legend__item.is-woman .member-board-sex-legend__dot { background: #f56c6c; }
|
||||
.member-board-sex-legend__name { flex: none; }
|
||||
.member-board-sex-legend__value { margin-left: 5px; color: #263548; font-weight: 600; }
|
||||
.member-board-chart-card { padding: 13px 12px 10px; box-sizing: border-box; }
|
||||
.member-board-radar-chart { width: 100%; height: 252px; }
|
||||
.member-board-column-chart { width: 100%; height: 238px; }
|
||||
.member-board-union-head { display: flex; align-items: center; justify-content: space-between; }
|
||||
.member-board-union-total { display: inline-flex; height: 28px; padding: 0 10px; align-items: center; border-radius: 14px; color: #397de0; background: #edf5ff; font-size: 11px; }
|
||||
.member-board-union-chart { width: 100%; height: 178px; margin-top: 4px; }
|
||||
.member-board-ranking { margin-top: 5px; overflow: hidden; border: 1px solid #edf1f6; border-radius: 8px; }
|
||||
.member-board-ranking__row { display: grid; min-height: 34px; padding: 0 10px; align-items: center; grid-template-columns: 38px minmax(0, 1fr) 58px; color: #526176; font-size: 11px; line-height: 18px; box-sizing: border-box; }
|
||||
.member-board-ranking__row:nth-child(odd) { background: #f8fbff; }
|
||||
.member-board-ranking__row.is-head { min-height: 36px; color: #354255; background: #f4f7fb; font-weight: 600; }
|
||||
.member-board-ranking__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.member-board-ranking__number { text-align: right; }
|
||||
.member-board-ranking__footer { display: flex; min-height: 38px; padding: 0 10px; align-items: center; justify-content: space-between; border-top: 1px solid #edf1f6; color: #8491a6; background: #fff; font-size: 11px; box-sizing: border-box; }
|
||||
.member-board-ranking__more { display: inline-flex; align-items: center; color: #1989fa; }
|
||||
.member-board-ranking__more .van-icon { margin-left: 3px; transition: transform .18s ease; }
|
||||
.member-board-ranking__more.is-open .van-icon { transform: rotate(180deg); }
|
||||
.member-board-update-time { display: flex; padding: 17px 0 2px; align-items: center; justify-content: center; color: #9aa7b8; font-size: 11px; line-height: 18px; }
|
||||
.member-board-update-time .van-icon { margin-right: 5px; color: #8fa1b8; font-size: 14px; }
|
||||
.member-board-skeleton { padding: 12px; }
|
||||
.member-board-skeleton__card { margin-bottom: 10px; padding: 16px; border-radius: 12px; background: #fff; box-sizing: border-box; box-shadow: 0 7px 20px rgba(55, 85, 126, .08); }
|
||||
.member-board-skeleton__card.is-summary { height: 132px; background: #dcecff; }
|
||||
.member-board-skeleton__card.is-chart { height: 224px; }
|
||||
.member-board-skeleton__card .van-skeleton { padding: 0; }
|
||||
@media (min-width: 600px) { .member-board-main, .member-board-skeleton { max-width: 520px; margin-right: auto; margin-left: auto; } }
|
||||
@media (max-width: 350px) {
|
||||
.member-board-main, .member-board-skeleton { padding-right: 10px; padding-left: 10px; }
|
||||
.member-board-grid { gap: 8px; }
|
||||
.member-board-mini-card { padding-right: 9px; padding-left: 9px; }
|
||||
.member-board-summary__value { font-size: 26px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="会员统计" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<van-row style="background-color: #f0f2f5" class="margin-top5" type="flex">
|
||||
<van-col span="12" class="top-col">
|
||||
<div class="col-title">会员数</div>
|
||||
<div class="top-col-member-number">
|
||||
{{memberNumberData.memberNum}}
|
||||
<span style="font-size: 14px"> 人</span>
|
||||
<div class="member-board-page">
|
||||
<van-nav-bar title="会员统计" left-text="返回" left-arrow placeholder fixed @click-left="historyBack"></van-nav-bar>
|
||||
<div v-if="pageLoading" class="member-board-skeleton">
|
||||
<div class="member-board-skeleton__card is-summary"><van-skeleton title :row="3"></van-skeleton></div>
|
||||
<div class="member-board-grid">
|
||||
<div class="member-board-skeleton__card is-chart"><van-skeleton title :row="4"></van-skeleton></div>
|
||||
<div class="member-board-skeleton__card is-chart"><van-skeleton title :row="4"></van-skeleton></div>
|
||||
</div>
|
||||
<div style="color: rgba(0, 0, 0, 0.85); margin-top: 20px; font-size: 14px; display: flex; align-items: center; justify-content: flex-end">
|
||||
年同比 {{memberNumberData.ratio}} 
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="caret-up"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
style="color: #67c23a"
|
||||
v-if="memberNumberData.diff>=0"
|
||||
viewBox="0 0 1024 1024"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z"
|
||||
></path>
|
||||
</svg>
|
||||
<div class="member-board-skeleton__card is-chart"><van-skeleton title :row="5"></van-skeleton></div>
|
||||
<div class="member-board-skeleton__card is-chart"><van-skeleton title :row="5"></van-skeleton></div>
|
||||
</div>
|
||||
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="caret-up"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
style="color: #f56c6c"
|
||||
v-else
|
||||
viewBox="0 0 1024 1024"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</van-col>
|
||||
<main v-show="!pageLoading" class="member-board-main">
|
||||
<section class="member-board-card member-board-summary">
|
||||
<div class="member-board-summary__number">
|
||||
<div class="member-board-summary__label">会员总数</div>
|
||||
<div class="member-board-summary__value">{{formatNumber(memberNumberData.memberNum)}}<span class="member-board-summary__unit">人</span></div>
|
||||
<div class="member-board-summary__ratio" :class="{'is-down': memberNumberData.diff < 0}">
|
||||
年同比 {{memberNumberData.ratio}}<van-icon name="play"></van-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="member-board-summary__trend">
|
||||
<div class="member-board-summary__trend-title">增长趋势</div>
|
||||
<div id="growthTrendChart" class="member-board-summary__chart"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-col span="12" class="top-col">
|
||||
<div class="col-title">增长趋势</div>
|
||||
<div class="top-col-chart" id="growthTrendChart"></div>
|
||||
</van-col>
|
||||
</van-row>
|
||||
<section class="member-board-grid">
|
||||
<div class="member-board-card member-board-mini-card">
|
||||
<div class="member-board-card__title">会员占比</div>
|
||||
<div class="member-board-mini-card__content">
|
||||
<div id="memberPercentageChart" class="member-board-mini-chart"></div>
|
||||
<div class="member-board-ring-value">{{memberPercentageText}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="member-board-card member-board-mini-card">
|
||||
<div class="member-board-card__title">性别占比</div>
|
||||
<div class="member-board-sex-layout">
|
||||
<div id="memberSexPercentageChart" class="member-board-sex-chart"></div>
|
||||
<div class="member-board-sex-legend">
|
||||
<div class="member-board-sex-legend__item"><span class="member-board-sex-legend__dot"></span><span class="member-board-sex-legend__name">男</span><span class="member-board-sex-legend__value">{{malePercentage}}</span></div>
|
||||
<div class="member-board-sex-legend__item is-woman"><span class="member-board-sex-legend__dot"></span><span class="member-board-sex-legend__name">女</span><span class="member-board-sex-legend__value">{{femalePercentage}}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<van-row style="background-color: #f0f2f5; margin-top: 5px" type="flex">
|
||||
<van-col span="12" class="top-col">
|
||||
<div class="col-title">会员占比</div>
|
||||
<div class="top-col-chart" id="memberPercentageChart"></div>
|
||||
</van-col>
|
||||
<van-col span="12" class="top-col">
|
||||
<div class="col-title">性别占比</div>
|
||||
<div class="top-col-chart" id="memberSexPercentageChart"></div>
|
||||
</van-col>
|
||||
</van-row>
|
||||
|
||||
<van-row style="background-color: #f0f2f5; margin-top: 5px" type="flex">
|
||||
<van-col span="24" class="center-col">
|
||||
<div class="col-title">在职状态</div>
|
||||
<div id="userStateMemberChart" style="width: 100%; height: 240px; box-sizing: border-box"></div>
|
||||
|
||||
<div class="col-title">人员类型</div>
|
||||
<div id="personTypeMemberChart" style="width: 100%; height: 240px; box-sizing: border-box"></div>
|
||||
</van-col>
|
||||
</van-row>
|
||||
|
||||
<van-row style="background-color: #f0f2f5; margin-top: 5px" type="flex">
|
||||
<van-col span="24" class="center-col">
|
||||
<div class="col-title">工会会员数</div>
|
||||
<div id="unionMemberChart" style="width: 100%; height: 200px"></div>
|
||||
|
||||
<div class="data-box">
|
||||
<!-- 表头 -->
|
||||
<van-row class="th-row">
|
||||
<van-col class="col-index">序号</van-col>
|
||||
<van-col class="col-name">工会名称</van-col>
|
||||
<van-col class="col-num">会员人数</van-col>
|
||||
</van-row>
|
||||
|
||||
<!-- 数据行 -->
|
||||
<van-row
|
||||
class="td-row"
|
||||
v-for="(item,index) in unionMember"
|
||||
:key="index"
|
||||
:style="{background:index%2?'#fafafa':'#fff'}"
|
||||
>
|
||||
<van-col class="col-index">{{ index+1 }}</van-col>
|
||||
<van-col class="col-name common-ellipsis" :title="item.unionname">
|
||||
{{ item.unionname }}
|
||||
</van-col>
|
||||
<van-col class="col-num">{{ item.value }}</van-col>
|
||||
</van-row>
|
||||
</div>
|
||||
</van-col>
|
||||
</van-row>
|
||||
<section class="member-board-card member-board-chart-card member-board-section">
|
||||
<div class="member-board-card__title">在职状态分布</div>
|
||||
<div id="userStateMemberChart" class="member-board-radar-chart"></div>
|
||||
</section>
|
||||
<section class="member-board-card member-board-chart-card member-board-section">
|
||||
<div class="member-board-card__title">人员类型分布</div>
|
||||
<div id="personTypeMemberChart" class="member-board-column-chart"></div>
|
||||
</section>
|
||||
<section class="member-board-card member-board-chart-card member-board-section">
|
||||
<div class="member-board-union-head">
|
||||
<div class="member-board-card__title">工会会员数统计(按工会)</div>
|
||||
<div class="member-board-union-total">共 {{unionMember.length}} 个工会</div>
|
||||
</div>
|
||||
<div id="unionMemberChart" class="member-board-union-chart"></div>
|
||||
<div class="member-board-ranking">
|
||||
<div class="member-board-ranking__row is-head"><span>排名</span><span>工会名称</span><span class="member-board-ranking__number">会员人数</span></div>
|
||||
<div v-for="(item, index) in visibleUnionMember" :key="item.unionCode || index" class="member-board-ranking__row">
|
||||
<span>{{index + 1}}</span><span class="member-board-ranking__name" :title="item.unionname">{{item.unionname}}</span><span class="member-board-ranking__number">{{item.value}}</span>
|
||||
</div>
|
||||
<div class="member-board-ranking__footer">
|
||||
<span>共 {{unionMember.length}} 个工会</span>
|
||||
<span v-if="unionMember.length > 5" class="member-board-ranking__more" :class="{'is-open': showAllUnion}" @click="toggleUnionRanking">
|
||||
{{showAllUnion ? "收起" : "查看更多"}}<van-icon name="arrow-down"></van-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div class="member-board-update-time"><van-icon name="clock-o"></van-icon>数据更新于 {{updateTime || "--"}}</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const chart = {
|
||||
growthTrendChart: undefined,
|
||||
memberPercentageChart: undefined,
|
||||
memberSexPercentageChart: undefined,
|
||||
unionMemberChart: undefined,
|
||||
personTypeMemberChart: undefined,
|
||||
userStateMemberChart: undefined
|
||||
|
||||
<script nonce="${cspNonce!}">
|
||||
const memberBoardCharts = {
|
||||
growthTrendChart: null,
|
||||
memberPercentageChart: null,
|
||||
memberSexPercentageChart: null,
|
||||
unionMemberChart: null,
|
||||
personTypeMemberChart: null,
|
||||
userStateMemberChart: null
|
||||
}
|
||||
|
||||
new Vue({
|
||||
el: "#app",
|
||||
data: {
|
||||
loading: {
|
||||
memberNumber: false,
|
||||
growthTrend: false,
|
||||
memberPercentage: false,
|
||||
memberSexPercentage: false,
|
||||
unionMember: false,
|
||||
personTypeMember: false,
|
||||
userStateMember: false
|
||||
},
|
||||
memberNumberData: {
|
||||
memberNum: "--",
|
||||
lastYearMemberNum: "--",
|
||||
ratio: "0.0%",
|
||||
diff: 0
|
||||
},
|
||||
memberPercentage: "--",
|
||||
unionMember: []
|
||||
data() {
|
||||
return {
|
||||
pageLoading: true,
|
||||
loading: {memberNumber: false, growthTrend: false, memberPercentage: false, memberSexPercentage: false, unionMember: false, personTypeMember: false, userStateMember: false},
|
||||
memberNumberData: {memberNum: 0, lastYearMemberNum: 0, ratio: "0.00%", diff: 0},
|
||||
memberPercentage: 0,
|
||||
growthTrendData: [],
|
||||
memberSexData: [],
|
||||
personTypeMemberData: [],
|
||||
userStateMemberData: [],
|
||||
unionChartData: [],
|
||||
unionMember: [],
|
||||
showAllUnion: false,
|
||||
updateTime: ""
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
memberPercentageText() { return (Number(this.memberPercentage || 0) * 100).toFixed(2) + "%" },
|
||||
malePercentage() { return this.getSexPercentage("男") },
|
||||
femalePercentage() { return this.getSexPercentage("女") },
|
||||
visibleUnionMember() { return this.showAllUnion ? this.unionMember : this.unionMember.slice(0, 5) }
|
||||
},
|
||||
methods: {
|
||||
historyBack,
|
||||
/**
|
||||
* 会员数
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
formatNumber(value) { return Number(value || 0).toLocaleString("zh-CN") },
|
||||
getSexPercentage(type) {
|
||||
const total = this.memberSexData.reduce((sum, item) => sum + Number(item.value || 0), 0)
|
||||
const current = this.memberSexData.find((item) => item.type === type)
|
||||
return total > 0 ? (Number(current ? current.value : 0) * 100 / total).toFixed(2) + "%" : "0.00%"
|
||||
},
|
||||
toggleUnionRanking() { this.$set(this, "showAllUnion", !this.showAllUnion) },
|
||||
formatUpdateTime(date) {
|
||||
const pad = (value) => String(value).padStart(2, "0")
|
||||
return date.getFullYear() + "-" + pad(date.getMonth() + 1) + "-" + pad(date.getDate()) + " " + pad(date.getHours()) + ":" + pad(date.getMinutes())
|
||||
},
|
||||
setLoading(key, value) { this.$set(this.loading, key, value) },
|
||||
getMemberNumber() {
|
||||
this.loading.memberNumber = true
|
||||
this.$axios.post("/platform/member/info/board/memberNumber").then((resp) => {
|
||||
this.setLoading("memberNumber", true)
|
||||
return this.$axios.post("/platform/member/info/board/memberNumber").then((resp) => {
|
||||
if (resp.code !== 0) { this.$toast.fail(resp.msg); return }
|
||||
const memberNum = Number(resp.data.memberNum || 0)
|
||||
const lastYearMemberNum = Number(resp.data.lastYearMemberNum || 0)
|
||||
const diff = memberNum - lastYearMemberNum
|
||||
const ratio = lastYearMemberNum > 0 ? Math.abs(diff) * 100 / lastYearMemberNum : 0
|
||||
this.$set(this, "memberNumberData", {memberNum, lastYearMemberNum, diff, ratio: ratio.toFixed(2) + "%"})
|
||||
}).finally(() => { this.setLoading("memberNumber", false) })
|
||||
},
|
||||
getGrowthTrend() {
|
||||
this.setLoading("growthTrend", true)
|
||||
return this.$axios.post("/platform/member/info/board/growthTrend").then((resp) => {
|
||||
if (resp.code === 0) this.$set(this, "growthTrendData", resp.data || [])
|
||||
else this.$toast.fail(resp.msg)
|
||||
}).finally(() => { this.setLoading("growthTrend", false) })
|
||||
},
|
||||
getMemberPercentage() {
|
||||
this.setLoading("memberPercentage", true)
|
||||
return this.$axios.post("/platform/member/info/board/memberPercentage").then((resp) => {
|
||||
if (resp.code === 0) this.$set(this, "memberPercentage", Number(resp.data || 0))
|
||||
else this.$toast.fail(resp.msg)
|
||||
}).finally(() => { this.setLoading("memberPercentage", false) })
|
||||
},
|
||||
getMemberSexPercentage() {
|
||||
this.setLoading("memberSexPercentage", true)
|
||||
return this.$axios.post("/platform/member/info/board/memberSexPercentage").then((resp) => {
|
||||
if (resp.code === 0) this.$set(this, "memberSexData", resp.data || [])
|
||||
else this.$toast.fail(resp.msg)
|
||||
}).finally(() => { this.setLoading("memberSexPercentage", false) })
|
||||
},
|
||||
getUnionMember() {
|
||||
this.setLoading("unionMember", true)
|
||||
return this.$axios.post("/platform/member/info/board/unionMember").then((resp) => {
|
||||
if (resp.code !== 0) { this.$toast.fail(resp.msg); return }
|
||||
const data = resp.data || {}
|
||||
const tableData = (data.tableData || []).slice().sort((first, second) => Number(second.value || 0) - Number(first.value || 0))
|
||||
this.$set(this, "unionChartData", data.chartData || [])
|
||||
this.$set(this, "unionMember", tableData)
|
||||
}).finally(() => { this.setLoading("unionMember", false) })
|
||||
},
|
||||
getPersonTypeMember() {
|
||||
this.setLoading("personTypeMember", true)
|
||||
return this.$axios.post("/platform/member/info/board/personTypeMember").then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
const {
|
||||
data: { memberNum, lastYearMemberNum }
|
||||
} = resp
|
||||
const diff = memberNum - lastYearMemberNum
|
||||
const ratio = (lastYearMemberNum ? (Math.abs(diff) / lastYearMemberNum) * 100 : (diff / 1) * 10).toFixed(2) + " %"
|
||||
this.memberNumberData = { memberNum, lastYearMemberNum, diff, ratio }
|
||||
this.loading.memberNumber = false
|
||||
} else {
|
||||
this.$toast.fail(resp.msg)
|
||||
const data = (resp.data || []).map((item) => ({label: item.name || item.label, value: Number(item.value || 0)}))
|
||||
this.$set(this, "personTypeMemberData", data)
|
||||
} else this.$toast.fail(resp.msg)
|
||||
}).finally(() => { this.setLoading("personTypeMember", false) })
|
||||
},
|
||||
getUserStateMember() {
|
||||
this.setLoading("userStateMember", true)
|
||||
return this.$axios.post("/platform/member/info/board/userStateMember").then((resp) => {
|
||||
if (resp.code === 0) {
|
||||
const data = (resp.data || []).map((item) => ({label: item.name || item.label, value: Number(item.value || 0)}))
|
||||
this.$set(this, "userStateMemberData", data)
|
||||
} else this.$toast.fail(resp.msg)
|
||||
}).finally(() => { this.setLoading("userStateMember", false) })
|
||||
},
|
||||
renderGrowthTrendChart() {
|
||||
memberBoardCharts.growthTrendChart = new G2Plot.Line("growthTrendChart", {
|
||||
data: this.growthTrendData, autoFit: true, xField: "label", yField: "value", smooth: true, color: "#ffffff", padding: [8, 5, 22, 5],
|
||||
lineStyle: {lineWidth: 2.5}, point: {size: 2.5, shape: "circle", style: {fill: "#ffffff", stroke: "#ffffff"}},
|
||||
xAxis: {line: null, tickLine: null, label: {style: {fill: "rgba(255,255,255,.78)", fontSize: 9}}}, yAxis: false,
|
||||
tooltip: {formatter: (datum) => ({name: datum.label + "年", value: datum.value + " 人"})}
|
||||
})
|
||||
memberBoardCharts.growthTrendChart.render()
|
||||
},
|
||||
renderMemberPercentageChart() {
|
||||
const percent = Math.max(0, Math.min(1, Number(this.memberPercentage || 0)))
|
||||
const data = [{type: "会员", value: percent}, {type: "其他", value: 1 - percent}]
|
||||
memberBoardCharts.memberPercentageChart = new G2Plot.Pie("memberPercentageChart", {
|
||||
data, autoFit: true, angleField: "value", colorField: "type", radius: .86, innerRadius: .72, legend: false, label: false, tooltip: false,
|
||||
color: ["#397ff0", "#edf2f8"], statistic: {title: false, content: false}
|
||||
})
|
||||
memberBoardCharts.memberPercentageChart.render()
|
||||
},
|
||||
renderMemberSexChart() {
|
||||
memberBoardCharts.memberSexPercentageChart = new G2Plot.Pie("memberSexPercentageChart", {
|
||||
data: this.memberSexData, autoFit: true, angleField: "value", colorField: "type", radius: .88, legend: false, label: false,
|
||||
color: ["#409eff", "#f56c6c"], interactions: [{type: "element-active"}]
|
||||
})
|
||||
memberBoardCharts.memberSexPercentageChart.render()
|
||||
},
|
||||
renderUserStateChart() {
|
||||
memberBoardCharts.userStateMemberChart = new G2Plot.Radar("userStateMemberChart", {
|
||||
data: this.userStateMemberData, autoFit: true, xField: "label", yField: "value", appendPadding: [10, 18, 8, 18], color: "#2f78ed",
|
||||
meta: {value: {alias: "会员数量", min: 0, nice: true}}, xAxis: {tickLine: null, label: {style: {fill: "#526176", fontSize: 11}}},
|
||||
yAxis: {label: false, grid: {alternateColor: "#f5f8fd"}}, point: {size: 3}, area: {style: {fillOpacity: .16}}
|
||||
})
|
||||
memberBoardCharts.userStateMemberChart.render()
|
||||
},
|
||||
// 人员类型名称按每行五个中文字符拆分,保证移动端横轴展示完整内容而不是省略号。
|
||||
formatPersonTypeAxisLabel(value) {
|
||||
const text = String(value || "")
|
||||
const lineLength = 5
|
||||
const lines = []
|
||||
for (let index = 0; index < text.length; index += lineLength) {
|
||||
lines.push(text.substring(index, index + lineLength))
|
||||
}
|
||||
return lines.join("\n")
|
||||
},
|
||||
renderPersonTypeChart() {
|
||||
memberBoardCharts.personTypeMemberChart = new G2Plot.Column("personTypeMemberChart", {
|
||||
data: this.personTypeMemberData, autoFit: true, xField: "label", yField: "value", color: "#397ff0", columnWidthRatio: .42, appendPadding: [8, 4, 36, 4],
|
||||
label: {position: "top", style: {fill: "#397ff0", fontSize: 10}},
|
||||
xAxis: {tickLine: null, label: {autoHide: false, autoRotate: false, style: {fill: "#526176", fontSize: 9}, formatter: (value) => this.formatPersonTypeAxisLabel(value)}},
|
||||
yAxis: {label: {style: {fill: "#8a97a8", fontSize: 9}}, grid: {line: {style: {stroke: "#edf1f6"}}}},
|
||||
tooltip: {formatter: (datum) => ({name: datum.label, value: datum.value + " 人"})}
|
||||
})
|
||||
memberBoardCharts.personTypeMemberChart.render()
|
||||
},
|
||||
renderUnionChart() {
|
||||
memberBoardCharts.unionMemberChart = new G2Plot.Column("unionMemberChart", {
|
||||
data: this.unionChartData, autoFit: true, xField: "unionname", yField: "value", color: "#397ff0", columnWidthRatio: .56, appendPadding: [10, 2, 4, 2], label: false, xAxis: false,
|
||||
yAxis: {label: {style: {fill: "#8a97a8", fontSize: 9}}, grid: {line: {style: {stroke: "#edf1f6"}}}},
|
||||
tooltip: {formatter: (datum) => ({name: datum.unionname, value: datum.value + " 人"})}
|
||||
})
|
||||
memberBoardCharts.unionMemberChart.render()
|
||||
},
|
||||
renderCharts() {
|
||||
this.destroyCharts()
|
||||
this.renderGrowthTrendChart(); this.renderMemberPercentageChart(); this.renderMemberSexChart(); this.renderUserStateChart(); this.renderPersonTypeChart(); this.renderUnionChart()
|
||||
},
|
||||
resizeCharts() {
|
||||
Object.keys(memberBoardCharts).forEach((key) => {
|
||||
const container = document.getElementById(key)
|
||||
if (memberBoardCharts[key] && container) {
|
||||
memberBoardCharts[key].changeSize(container.clientWidth, container.clientHeight)
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 增长趋势
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async getGrowthTrend() {
|
||||
this.loading.growthTrend = true
|
||||
this.$axios.post("/platform/member/info/board/growthTrend").then((resp) => {
|
||||
this.loading.growthTrend = false
|
||||
if (resp.code === 0) {
|
||||
const { data } = resp
|
||||
|
||||
const labels = data.map((v) => v.label)
|
||||
const values = data.map((v) => v.value)
|
||||
if (chart.growthTrendChart) {
|
||||
chart.growthTrendChart.changeData(values)
|
||||
return
|
||||
}
|
||||
|
||||
chart.growthTrendChart = new G2Plot.TinyArea("growthTrendChart", {
|
||||
autoFit: true,
|
||||
data: values,
|
||||
smooth: true,
|
||||
showContent: true,
|
||||
areaStyle: {
|
||||
fill: "#d6e3fd"
|
||||
},
|
||||
tooltip: {
|
||||
customContent: function (i, data) {
|
||||
if (labels[i]) {
|
||||
return labels[i] + "-" + data[0]?.data?.y + "人"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
}
|
||||
})
|
||||
chart.growthTrendChart.render()
|
||||
} else {
|
||||
this.$toast.fail(resp.msg)
|
||||
}
|
||||
destroyCharts() {
|
||||
Object.keys(memberBoardCharts).forEach((key) => {
|
||||
if (memberBoardCharts[key]) { memberBoardCharts[key].destroy(); memberBoardCharts[key] = null }
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 会员占比
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async getMemberPercentage() {
|
||||
this.loading.memberPercentage = true
|
||||
this.$axios.post("/platform/member/info/board/memberPercentage").then((resp) => {
|
||||
this.loading.memberPercentage = false
|
||||
if (resp.code === 0) {
|
||||
const { data } = resp
|
||||
this.memberPercentage = data.toFixed(2)
|
||||
if (chart.memberPercentageChart) {
|
||||
chart.memberPercentageChart.changeData(data)
|
||||
return
|
||||
}
|
||||
chart.memberPercentageChart = new G2Plot.Liquid("memberPercentageChart", {
|
||||
outline: {
|
||||
border: 4,
|
||||
distance: 8
|
||||
},
|
||||
wave: {
|
||||
length: 128
|
||||
},
|
||||
autoFit: true,
|
||||
percent: data,
|
||||
statistic: {
|
||||
content: {
|
||||
style: {
|
||||
fontSize: 16
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
chart.memberPercentageChart.render()
|
||||
} else {
|
||||
this.$toast.fail(resp.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 男女占比
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async getMemberSexPercentage() {
|
||||
this.loading.memberSexPercentage = true
|
||||
this.$axios.post("/platform/member/info/board/memberSexPercentage").then((resp) => {
|
||||
this.loading.memberSexPercentage = false
|
||||
if (resp.code === 0) {
|
||||
const { data } = resp
|
||||
if (chart.memberSexPercentageChart) {
|
||||
chart.memberSexPercentageChart.changeData(data)
|
||||
return
|
||||
}
|
||||
|
||||
chart.memberSexPercentageChart = new G2Plot.Pie("memberSexPercentageChart", {
|
||||
data,
|
||||
angleField: "value",
|
||||
colorField: "type",
|
||||
legend: false,
|
||||
label: {
|
||||
formatter: () => ""
|
||||
},
|
||||
interactions: [{ type: "element-active" }],
|
||||
color: ["#409EFF", "#F56C6C"]
|
||||
})
|
||||
chart.memberSexPercentageChart.render()
|
||||
} else {
|
||||
this.$toast.fail(resp.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 各工会会员数
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async getUnionMember() {
|
||||
this.loading.unionMember = true
|
||||
this.$axios.post("/platform/member/info/board/unionMember").then((resp) => {
|
||||
this.loading.unionMember = false
|
||||
if (resp.code === 0) {
|
||||
const { chartData, tableData } = resp.data
|
||||
|
||||
this.unionMember = tableData
|
||||
|
||||
const labels = chartData.map((v) => v.unionname)
|
||||
const values = chartData.map((v) => v.value)
|
||||
|
||||
if (chart.unionMemberChart) {
|
||||
chart.unionMemberChart.changeData(values)
|
||||
return
|
||||
}
|
||||
|
||||
chart.unionMemberChart = new G2Plot.Column("unionMemberChart", {
|
||||
data: chartData,
|
||||
autoFit: true,
|
||||
xField: "unionname",
|
||||
yField: "value",
|
||||
label: {
|
||||
// 可手动配置 label 数据标签位置
|
||||
position: "middle", // 'top', 'bottom', 'middle',
|
||||
// 配置样式
|
||||
style: {
|
||||
fill: "#FFFFFF",
|
||||
opacity: 0.6
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
label: {
|
||||
autoHide: true,
|
||||
autoRotate: false
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
label: {
|
||||
alias: "类型"
|
||||
},
|
||||
value: {
|
||||
alias: "会员数"
|
||||
}
|
||||
}
|
||||
})
|
||||
chart.unionMemberChart.render()
|
||||
} else {
|
||||
this.$message.warning(resp.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据人员类型查找会员数
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async getPersonTypeMember() {
|
||||
this.loading.personTypeMember = true
|
||||
this.$axios.post("/platform/member/info/board/personTypeMember").then((resp) => {
|
||||
this.loading.personTypeMember = false
|
||||
if (resp.code === 0) {
|
||||
const { data } = resp
|
||||
|
||||
if (chart.personTypeMemberChart) {
|
||||
chart.personTypeMemberChart.changeData(data)
|
||||
return
|
||||
}
|
||||
|
||||
chart.personTypeMemberChart = new G2Plot.Column("personTypeMemberChart", {
|
||||
data,
|
||||
autoFit: true,
|
||||
xField: "label",
|
||||
yField: "value",
|
||||
label: {
|
||||
// 可手动配置 label 数据标签位置
|
||||
position: "middle", // 'top', 'bottom', 'middle',
|
||||
// 配置样式
|
||||
style: {
|
||||
fill: "#FFFFFF",
|
||||
opacity: 0.6
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
label: {
|
||||
autoHide: true,
|
||||
autoRotate: false
|
||||
}
|
||||
},
|
||||
meta: {
|
||||
label: {
|
||||
alias: "类型"
|
||||
},
|
||||
value: {
|
||||
alias: "会员数"
|
||||
}
|
||||
}
|
||||
})
|
||||
chart.personTypeMemberChart.render()
|
||||
} else {
|
||||
this.$toast.fail(resp.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 根据在职状态查找会员数
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async getUserStateMember() {
|
||||
this.loading.userStateMember = true
|
||||
this.$axios.post("/platform/member/info/board/userStateMember").then((resp) => {
|
||||
this.loading.userStateMember = false
|
||||
if (resp.code === 0) {
|
||||
const { data } = resp
|
||||
|
||||
if (chart.userStateMemberChart) {
|
||||
chart.userStateMemberChart.changeData(data)
|
||||
return
|
||||
}
|
||||
|
||||
chart.userStateMemberChart = new G2Plot.Radar("userStateMemberChart", {
|
||||
data,
|
||||
xField: "label",
|
||||
yField: "value",
|
||||
appendPadding: [0, 10, 0, 10],
|
||||
meta: {
|
||||
value: {
|
||||
alias: "会员数量",
|
||||
min: 0,
|
||||
nice: true,
|
||||
formatter: (v) => parseInt(v)
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
tickLine: null
|
||||
},
|
||||
yAxis: {
|
||||
label: false,
|
||||
grid: {
|
||||
alternateColor: "rgba(0, 0, 0, 0.04)"
|
||||
}
|
||||
},
|
||||
// 开启辅助点
|
||||
point: {
|
||||
size: 2
|
||||
},
|
||||
area: {}
|
||||
})
|
||||
chart.userStateMemberChart.render()
|
||||
} else {
|
||||
this.$toast.fail(resp.msg)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
initData() {
|
||||
this.getMemberNumber()
|
||||
this.getGrowthTrend()
|
||||
this.getMemberPercentage()
|
||||
this.getMemberSexPercentage()
|
||||
this.getUnionMember()
|
||||
this.getPersonTypeMember()
|
||||
this.getUserStateMember()
|
||||
const requests = [this.getMemberNumber(), this.getGrowthTrend(), this.getMemberPercentage(), this.getMemberSexPercentage(), this.getUnionMember(), this.getPersonTypeMember(), this.getUserStateMember()]
|
||||
Promise.all(requests).then(() => { this.$set(this, "updateTime", this.formatUpdateTime(new Date())) }).finally(() => {
|
||||
this.$set(this, "pageLoading", false)
|
||||
this.$nextTick(() => { this.renderCharts() })
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initData()
|
||||
}
|
||||
mounted() { window.addEventListener("resize", this.resizeCharts); this.initData() },
|
||||
beforeDestroy() { window.removeEventListener("resize", this.resizeCharts); this.destroyCharts() }
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
|
||||
+403
-66
@@ -1,53 +1,332 @@
|
||||
<!--#
|
||||
layout("/layouts/platform_h5.html"){
|
||||
#-->
|
||||
<style></style>
|
||||
<style id="style-member-info-group-h5">
|
||||
<!--#include("../../theme.css"){}#-->
|
||||
|
||||
body,
|
||||
.member-archive-page {
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-archive-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.member-archive-page .van-nav-bar {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.member-archive-page .van-nav-bar__title {
|
||||
color: #172033;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-archive-page .van-nav-bar .van-icon,
|
||||
.member-archive-page .van-nav-bar__text {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.member-archive-sticky {
|
||||
padding: 22px 12px 1px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-archive-search {
|
||||
margin: 0 0 8px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .1);
|
||||
}
|
||||
|
||||
.member-archive-search .van-search__content {
|
||||
height: 42px;
|
||||
padding-left: 12px;
|
||||
align-items: center;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.member-archive-search .van-field__control {
|
||||
color: #263548;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-archive-search .van-field__control::placeholder {
|
||||
color: #a7b0bf;
|
||||
}
|
||||
|
||||
.member-archive-filter {
|
||||
margin: 0 0 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .08);
|
||||
transition: border-radius .18s ease;
|
||||
}
|
||||
|
||||
.member-archive-filter.is-open {
|
||||
border-radius: 10px 10px 0 0;
|
||||
}
|
||||
|
||||
.member-archive-filter .van-dropdown-menu__bar,
|
||||
.member-archive-filter .van-dropdown-menu__item,
|
||||
.member-archive-filter .van-dropdown-menu__title {
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.member-archive-filter .van-dropdown-menu__bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.member-archive-filter .van-dropdown-menu__title {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: #66758a;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.member-archive-filter .van-dropdown-menu__title--active,
|
||||
.member-archive-filter .van-dropdown-item__option--active,
|
||||
.member-archive-filter .van-dropdown-item__option--active .van-dropdown-item__icon {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.member-archive-filter .van-dropdown-item__content {
|
||||
width: calc(100% - 24px);
|
||||
margin: 0 12px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0 0 12px 12px;
|
||||
box-shadow: 0 10px 24px rgba(31, 65, 108, .14);
|
||||
}
|
||||
|
||||
.member-archive-filter .van-dropdown-item__option {
|
||||
display: flex;
|
||||
min-height: 48px;
|
||||
padding: 0 16px;
|
||||
align-items: center;
|
||||
color: #46566c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-archive-content {
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.member-archive-summary {
|
||||
display: inline-flex;
|
||||
height: 28px;
|
||||
margin: 0 0 10px;
|
||||
padding: 0 11px;
|
||||
align-items: center;
|
||||
border-radius: 14px;
|
||||
color: #397de0;
|
||||
background-color: #e8f2ff;
|
||||
font-size: 12px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.member-archive-list .table-list-container {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.member-archive-list .empty-state {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.member-archive-empty {
|
||||
display: flex;
|
||||
min-height: 280px;
|
||||
padding: 46px 18px 36px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.member-archive-empty img {
|
||||
display: block;
|
||||
width: 86%;
|
||||
max-width: 290px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.member-archive-empty__title {
|
||||
margin-top: 14px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-archive-empty__hint {
|
||||
margin-top: 5px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-archive-card-header {
|
||||
display: flex;
|
||||
margin-bottom: 7px;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.member-archive-card-heading {
|
||||
min-width: 0;
|
||||
padding-right: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.member-archive-card-title {
|
||||
overflow: hidden;
|
||||
color: #253247;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-archive-card-code {
|
||||
margin-top: 1px;
|
||||
color: #9ba6b6;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-archive-status {
|
||||
display: inline-flex;
|
||||
min-height: 24px;
|
||||
padding: 3px 9px;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
border-radius: 12px;
|
||||
color: #1989fa;
|
||||
background-color: #eaf4ff;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.member-archive-page .table-list-container .table-list-item .action-btn .van-icon {
|
||||
margin-right: 6px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.member-archive-page-skeleton {
|
||||
min-height: calc(100vh - 46px);
|
||||
padding: 22px 12px;
|
||||
box-sizing: border-box;
|
||||
background-color: #f3f7fd;
|
||||
}
|
||||
|
||||
.member-archive-page-skeleton__filter,
|
||||
.member-archive-page-skeleton__card {
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .07);
|
||||
}
|
||||
|
||||
.member-archive-page-skeleton__filter {
|
||||
min-height: 96px;
|
||||
}
|
||||
|
||||
.member-archive-page-skeleton__card {
|
||||
min-height: 154px;
|
||||
}
|
||||
|
||||
.member-archive-page-skeleton .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
.member-archive-content,
|
||||
.member-archive-sticky {
|
||||
padding-right: 10px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="会员查询" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
|
||||
<van-sticky offset-top="46px">
|
||||
<van-search
|
||||
v-model="pageForm.searchKeyword"
|
||||
placeholder="请输入工号或者姓名进行查询"
|
||||
show-action
|
||||
:reverse-color="false"
|
||||
input-align="left"
|
||||
@search="doSearch">
|
||||
<template #action>
|
||||
<div @click="doSearch">搜索</div>
|
||||
</template>
|
||||
</van-search>
|
||||
<van-dropdown-menu :close-on-click-outside="false" :close-on-click-overlay="false">
|
||||
<van-dropdown-item :options="unionList" @change="unionChange"
|
||||
v-model="pageForm.unionId"></van-dropdown-item>
|
||||
<van-dropdown-item :options="unitList" @change="doSearch" v-model="pageForm.unitId"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</van-sticky>
|
||||
<div class="member-h5-page member-archive-page">
|
||||
<van-nav-bar title="会员档案" left-text="返回" left-arrow @click-left="handlePageBack" placeholder fixed></van-nav-bar>
|
||||
<div class="member-archive-page-skeleton" v-if="pageLoading">
|
||||
<div class="member-archive-page-skeleton__filter"><van-skeleton title :row="2"></van-skeleton></div>
|
||||
<div class="member-archive-page-skeleton__cards">
|
||||
<div class="member-archive-page-skeleton__card" v-for="index in 3" :key="'archive-page-skeleton-' + index">
|
||||
<van-skeleton title :row="4"></van-skeleton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="!pageLoading">
|
||||
<van-sticky :offset-top="46">
|
||||
<div class="member-archive-sticky">
|
||||
<van-search v-model="pageForm.searchKeyword" class="member-archive-search"
|
||||
placeholder="请输入工号或姓名搜索" shape="round" clearable
|
||||
@search="doSearch" @clear="doSearch"></van-search>
|
||||
<van-dropdown-menu class="member-archive-filter" :class="{'is-open': filterOpened}"
|
||||
active-color="#1989fa" :close-on-click-outside="false"
|
||||
:close-on-click-overlay="false">
|
||||
<van-dropdown-item v-model="pageForm.unionId" :options="unionList" @change="unionChange"
|
||||
@open="setFilterOpened(true)" @close="setFilterOpened(false)"></van-dropdown-item>
|
||||
<van-dropdown-item v-model="pageForm.unitId" :options="unitList" @change="doSearch"
|
||||
@open="setFilterOpened(true)" @close="setFilterOpened(false)"></van-dropdown-item>
|
||||
</van-dropdown-menu>
|
||||
</div>
|
||||
</van-sticky>
|
||||
|
||||
|
||||
<table-list api="/platform/member/info/group/pageData" :page_form.sync="pageForm" ref="tableListRef" @ready="onReady">
|
||||
<main class="member-archive-content">
|
||||
<div class="member-archive-summary">共 {{pageForm.totalCount}} 名会员</div>
|
||||
<div class="member-archive-list">
|
||||
<div v-if="pageForm.totalCount === 0" class="member-archive-empty">
|
||||
<img src="/assets/mobile/img/home/v4/app-center-empty-v4.png" alt="暂无会员档案">
|
||||
<div class="member-archive-empty__title">暂无会员档案</div>
|
||||
<div class="member-archive-empty__hint">请尝试调整工会、单位或搜索关键词</div>
|
||||
</div>
|
||||
<table-list v-show="!initialLoading" api="/platform/member/info/group/pageData" :page_form.sync="pageForm" ref="tableListRef" title="username" :show_loading_overlay="false" @loading-change="onListLoadingChange" @ready="onReady">
|
||||
<template #header="{index,row}">
|
||||
<div class="member-archive-card-header">
|
||||
<div class="member-archive-card-heading">
|
||||
<div class="member-archive-card-title">{{row.username || '--'}}</div>
|
||||
<div class="member-archive-card-code">工号:{{row.loginname || '--'}}</div>
|
||||
</div>
|
||||
<span class="member-archive-status">会员</span>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot="{index,row}">
|
||||
<table-column label="姓名">{{row.username}}</table-column>
|
||||
<table-column label="工号">{{row.loginname}}</table-column>
|
||||
<table-column label="性别">{{row.sex}}</table-column>
|
||||
<table-column label="所属工会">{{row.unionName}}</table-column>
|
||||
<table-column label="所属单位">{{row.unitName}}</table-column>
|
||||
<table-column label="性别">{{row.sex || '--'}}</table-column>
|
||||
<table-column label="所属工会">{{row.unionName || '--'}}</table-column>
|
||||
<table-column label="所属单位">{{row.unitName || '--'}}</table-column>
|
||||
</template>
|
||||
<template #actions="{index,row}">
|
||||
<div class="action-btn" @click="viewInfo(row)">
|
||||
<i class="fa fa-eye"></i>
|
||||
<van-icon name="eye-o"></van-icon>
|
||||
<span>查看</span>
|
||||
</div>
|
||||
</template>
|
||||
</table-list>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<div :style="{color:'#1890ff'}" style="text-align: right; position: fixed; bottom: 20px; right: 20px">
|
||||
<van-button :color="'#1890ff'" hairline size="small" type="primary">总人数:{{pageForm.totalCount}}人
|
||||
</van-button>
|
||||
</div>
|
||||
|
||||
<van-action-sheet v-model="infoShow" title="会员详细信息">
|
||||
<van-action-sheet v-model="infoShow" class="member-info-sheet" title="会员详细信息" :close-on-click-overlay="false" @close="handleInfoSheetClose">
|
||||
<member-info ref="memberInfoRef" :user-id="userId"></member-info>
|
||||
</van-action-sheet>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script nonce="${cspNonce!}">
|
||||
<!--#include("../../common/mobileMemberInfo.js"){}#-->
|
||||
@@ -67,69 +346,127 @@ layout("/layouts/platform_h5.html"){
|
||||
unitList: [],
|
||||
|
||||
userId: "",
|
||||
infoShow: false
|
||||
infoShow: false,
|
||||
initialLoading: true,
|
||||
pageLoading: true,
|
||||
filterOpened: false,
|
||||
filterReady: false,
|
||||
tableReady: false,
|
||||
initialSearchStarted: false,
|
||||
historyLayerPageKey: "member-info-group"
|
||||
}
|
||||
},
|
||||
components: {
|
||||
"member-info": MOBILE_MEMBER_INFO
|
||||
},
|
||||
methods: {
|
||||
historyBack,
|
||||
// 同步筛选弹层展开状态,用于保持与提案预审核一致的筛选栏圆角。
|
||||
setFilterOpened(opened) {
|
||||
this.$set(this, "filterOpened", opened)
|
||||
},
|
||||
|
||||
handlePageBack() {
|
||||
if (window.h5HistoryLayerManager.stack.length) {
|
||||
window.h5HistoryLayerManager.close()
|
||||
return
|
||||
}
|
||||
historyBack()
|
||||
},
|
||||
|
||||
registerHistoryLayers() {
|
||||
// 会员详情作为页面唯一弹层,返回键先关闭详情再离开会员档案页面。
|
||||
window.h5HistoryLayerManager.register(this.historyLayerPageKey, (stack) => {
|
||||
this.$set(this, "infoShow", stack.includes("member-info"))
|
||||
})
|
||||
},
|
||||
|
||||
onReady() {
|
||||
this.$set(this, "tableReady", true)
|
||||
this.tryInitialSearch()
|
||||
},
|
||||
|
||||
// 工会、单位筛选项与列表组件都完成初始化后,只触发一次首次查询。
|
||||
tryInitialSearch() {
|
||||
if (!this.filterReady || !this.tableReady || this.initialSearchStarted) return
|
||||
this.$set(this, "initialSearchStarted", true)
|
||||
this.doSearch()
|
||||
},
|
||||
|
||||
viewInfo(row) {
|
||||
this.userId = row.id
|
||||
this.infoShow = true
|
||||
this.$set(this, "userId", row.id)
|
||||
window.h5HistoryLayerManager.open("member-info")
|
||||
},
|
||||
handleInfoSheetClose() {
|
||||
if (window.h5HistoryLayerManager.stack.includes("member-info")) {
|
||||
window.h5HistoryLayerManager.close("member-info")
|
||||
}
|
||||
},
|
||||
onListLoadingChange(state) {
|
||||
// 首屏和重新筛选时以卡片骨架替代旧列表,避免数据切换期间残留。
|
||||
if (state.initial) {
|
||||
this.$set(this, "initialLoading", state.loading)
|
||||
if (!state.loading && this.initialSearchStarted) {
|
||||
this.$set(this, "pageLoading", false)
|
||||
}
|
||||
}
|
||||
},
|
||||
unionChange() {
|
||||
this.$set(this.pageForm, "unitId", null)
|
||||
this.flushUnits()
|
||||
this.doSearch()
|
||||
this.flushUnits().then(() => {
|
||||
this.doSearch()
|
||||
})
|
||||
},
|
||||
doSearch() {
|
||||
this.$nextTick(() => {
|
||||
this.pageForm.pageNumber = 1
|
||||
this.pageForm.totalCount = 0
|
||||
this.$set(this.pageForm, "pageNumber", 1)
|
||||
this.$set(this.pageForm, "totalCount", 0)
|
||||
this.$refs.tableListRef.doSearch()
|
||||
})
|
||||
},
|
||||
async initUnion() {
|
||||
initUnion() {
|
||||
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||
const unionId = hasAdmin ? null : this.$store.state.user.union.id
|
||||
this.unionList = await this.$businessTool.listUnion(unionId)
|
||||
this.unionList.forEach((v) => {
|
||||
v.text = v.name
|
||||
v.value = v.id
|
||||
return this.$businessTool.listUnion(unionId).then((data) => {
|
||||
this.unionList = data
|
||||
this.unionList.forEach((v) => {
|
||||
v.text = v.name
|
||||
v.value = v.id
|
||||
})
|
||||
if (hasAdmin) {
|
||||
this.unionList.unshift({ text: "全部工会", value: null })
|
||||
}
|
||||
if (this.unionList.length > 0) {
|
||||
this.$set(this.pageForm, "unionId", this.unionList[0].value)
|
||||
}
|
||||
})
|
||||
if (hasAdmin) {
|
||||
this.unionList.unshift({ text: "全部工会", value: null })
|
||||
}
|
||||
if (this.unionList && this.unionList.length > 0) {
|
||||
this.$set(this.pageForm, "unionId", this.unionList[0].value)
|
||||
}
|
||||
},
|
||||
async flushUnits() {
|
||||
flushUnits() {
|
||||
const hasAdmin = this.$auth.hasRoleOr(["SYSADMIN", "SCHOOL_UNION_ADMIN"])
|
||||
const unionId = hasAdmin ? this.pageForm.unionId : this.$store.state.user.union.id
|
||||
this.unitList = await this.$businessTool.listUnit(unionId)
|
||||
this.unitList.forEach((v) => {
|
||||
v.text = v.name
|
||||
v.value = v.id
|
||||
return this.$businessTool.listUnit(unionId).then((data) => {
|
||||
this.unitList = data
|
||||
this.unitList.forEach((v) => {
|
||||
v.text = v.name
|
||||
v.value = v.id
|
||||
})
|
||||
if (hasAdmin && !this.pageForm.unionId) {
|
||||
this.unitList.unshift({ text: "全部单位", value: null })
|
||||
}
|
||||
if (this.unitList.length > 0) {
|
||||
this.$set(this.pageForm, "unitId", this.unitList[0].value)
|
||||
}
|
||||
})
|
||||
if (hasAdmin && !this.pageForm.unionId) {
|
||||
this.unitList.unshift({ text: "全部单位", value: null })
|
||||
}
|
||||
if (this.unitList && this.unitList.length > 0) {
|
||||
this.$set(this.pageForm, "unitId", this.unitList[0].value)
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.initUnion()
|
||||
this.flushUnits()
|
||||
this.registerHistoryLayers()
|
||||
this.initUnion().then(() => this.flushUnits()).finally(() => {
|
||||
this.$set(this, "filterReady", true)
|
||||
this.tryInitialSearch()
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.h5HistoryLayerManager.unregister(this.historyLayerPageKey)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,495 @@
|
||||
:root {
|
||||
--member-primary: #1989fa;
|
||||
--member-page-bg: #f3f7fd;
|
||||
--member-text: #263548;
|
||||
--member-muted: #8c98aa;
|
||||
--member-border: #e8eef6;
|
||||
--color-primary: #1989fa;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--member-page-bg);
|
||||
}
|
||||
|
||||
.member-h5-page {
|
||||
min-height: 100vh;
|
||||
padding-bottom: calc(24px + env(safe-area-inset-bottom));
|
||||
box-sizing: border-box;
|
||||
color: var(--member-text);
|
||||
background: var(--member-page-bg);
|
||||
}
|
||||
|
||||
.member-h5-page.has-fixed-actions {
|
||||
padding-bottom: calc(78px + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.member-h5-page .van-nav-bar {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.member-h5-page .van-nav-bar__title {
|
||||
color: #1f2937;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-h5-page .van-nav-bar .van-icon,
|
||||
.member-h5-page .van-nav-bar__text {
|
||||
color: var(--member-primary);
|
||||
}
|
||||
|
||||
.member-hero {
|
||||
position: relative;
|
||||
height: 116px;
|
||||
padding: 18px 18px 0;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
background-color: #edf5ff;
|
||||
background-image: url("/assets/mobile/img/home/v4/hero-campus.png");
|
||||
background-position: 66% 46%;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.member-hero::after {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background: rgba(242, 247, 255, .76);
|
||||
content: "";
|
||||
}
|
||||
|
||||
.member-hero__content {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.member-hero__title {
|
||||
color: var(--member-primary);
|
||||
font-size: 23px;
|
||||
font-weight: 700;
|
||||
line-height: 30px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.member-hero__subtitle {
|
||||
margin-top: 2px;
|
||||
color: #718096;
|
||||
font-size: 11px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-page-main {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
margin-top: -34px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.member-toolbar {
|
||||
padding: 10px;
|
||||
border: 1px solid var(--member-border);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, .98);
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .09);
|
||||
}
|
||||
|
||||
.member-toolbar .van-search {
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.member-toolbar .van-search__content {
|
||||
height: 42px;
|
||||
align-items: center;
|
||||
border-radius: 10px;
|
||||
background: #f5f8fc;
|
||||
}
|
||||
|
||||
.member-toolbar .van-field__control {
|
||||
color: var(--member-text);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-toolbar .van-search__action {
|
||||
padding: 0 4px 0 12px;
|
||||
color: var(--member-primary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-toolbar .van-dropdown-menu {
|
||||
margin-top: 8px;
|
||||
/* Vant 下拉选项弹层位于菜单内部,吸顶状态下必须允许弹层超出筛选卡片显示。 */
|
||||
overflow: visible;
|
||||
border-top: 1px solid #edf1f6;
|
||||
}
|
||||
|
||||
.member-toolbar .van-dropdown-menu__bar {
|
||||
height: 42px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.member-toolbar .van-dropdown-menu__title {
|
||||
color: #66758a;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.member-list-section {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.member-list-section .table-list-container {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.member-list-section .table-list-item {
|
||||
border-color: var(--member-border) !important;
|
||||
border-radius: 12px !important;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08) !important;
|
||||
}
|
||||
|
||||
.member-list-section .item-title {
|
||||
color: #263548 !important;
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
.member-list-section .action-btn {
|
||||
color: var(--member-primary) !important;
|
||||
background: #eaf4ff !important;
|
||||
}
|
||||
|
||||
.member-list-section .action-btn.delete {
|
||||
color: #e95757 !important;
|
||||
background: #fff0f0 !important;
|
||||
}
|
||||
|
||||
.member-empty {
|
||||
display: flex;
|
||||
min-height: 280px;
|
||||
padding: 20px 18px 30px;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.member-empty img {
|
||||
display: block;
|
||||
width: 84%;
|
||||
max-width: 290px;
|
||||
height: auto;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.member-empty__title {
|
||||
margin-top: -8px;
|
||||
color: #50627a;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.member-empty__hint {
|
||||
margin-top: 6px;
|
||||
color: #9aa7b8;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.member-list-skeleton {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.member-list-skeleton__card {
|
||||
min-height: 154px;
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 7px 20px rgba(55, 85, 126, .08);
|
||||
}
|
||||
|
||||
.member-list-skeleton__card .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.member-list-skeleton__card .van-skeleton__title {
|
||||
height: 17px;
|
||||
}
|
||||
|
||||
.member-list-skeleton__card .van-skeleton__row {
|
||||
height: 12px;
|
||||
margin-top: 13px;
|
||||
}
|
||||
|
||||
/* 页面首次进入时统一遮住尚未完成初始化的横幅、筛选栏和列表,避免返回页面时出现空筛选项。 */
|
||||
.member-page-skeleton {
|
||||
min-height: calc(100vh - 46px);
|
||||
padding: 12px;
|
||||
box-sizing: border-box;
|
||||
background: var(--member-page-bg);
|
||||
}
|
||||
|
||||
.member-page-skeleton__hero {
|
||||
height: 82px;
|
||||
margin-bottom: 10px;
|
||||
padding: 18px;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #e4f1ff 0%, #f2f7ff 100%);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.member-page-skeleton__toolbar {
|
||||
min-height: 96px;
|
||||
margin-bottom: 10px;
|
||||
padding: 14px;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 5px 16px rgba(43, 73, 112, .07);
|
||||
}
|
||||
|
||||
.member-page-skeleton__toolbar .van-skeleton,
|
||||
.member-page-skeleton__hero .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.member-page-skeleton__cards .member-list-skeleton {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.member-count-chip {
|
||||
display: inline-flex;
|
||||
height: 28px;
|
||||
margin: 10px 0 0;
|
||||
padding: 0 11px;
|
||||
align-items: center;
|
||||
border-radius: 14px;
|
||||
color: #397de0;
|
||||
background: #edf5ff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.member-form-intro {
|
||||
display: flex;
|
||||
min-height: 58px;
|
||||
margin-bottom: 10px;
|
||||
padding: 11px 12px;
|
||||
align-items: flex-start;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #dfeafb;
|
||||
border-radius: 10px;
|
||||
background: rgba(246, 250, 255, .98);
|
||||
box-shadow: 0 3px 10px rgba(53, 98, 154, .08);
|
||||
}
|
||||
|
||||
.member-form-intro .van-icon {
|
||||
margin: 1px 9px 0 0;
|
||||
color: var(--member-primary);
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
.member-form-intro__title {
|
||||
color: var(--member-primary);
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-form-intro__text {
|
||||
margin-top: 2px;
|
||||
color: #8a97a8;
|
||||
font-size: 10px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
.member-application-form.form-container {
|
||||
padding-bottom: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.member-application-form .form-section {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--member-border);
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
box-shadow: 0 5px 16px rgba(55, 85, 126, .07);
|
||||
}
|
||||
|
||||
.member-application-form .van-cell-group__title {
|
||||
padding: 12px 14px 8px 21px;
|
||||
color: #354255;
|
||||
background: #fff;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.member-application-form .van-cell-group__title::before {
|
||||
top: 15px;
|
||||
bottom: 11px;
|
||||
left: 12px;
|
||||
width: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.member-application-form .van-cell {
|
||||
min-height: 44px;
|
||||
padding: 10px 14px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.member-application-form .van-field__label {
|
||||
width: 84px;
|
||||
color: #596779;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.member-application-form .van-field__control,
|
||||
.member-application-form .van-field__value {
|
||||
color: #4f5d70;
|
||||
font-size: 12px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.member-form-actions,
|
||||
.member-approval-actions {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
display: flex;
|
||||
gap: 9px;
|
||||
padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
|
||||
border-top: 1px solid #edf1f6;
|
||||
background: rgba(255, 255, 255, .98);
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 -4px 14px rgba(50, 78, 112, .06);
|
||||
}
|
||||
|
||||
.member-form-actions .van-button,
|
||||
.member-approval-actions .van-button {
|
||||
height: 42px;
|
||||
margin: 0;
|
||||
border-radius: 14px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.member-form-actions .member-save-button {
|
||||
color: var(--member-primary);
|
||||
border-color: var(--member-primary);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.member-form-actions .member-submit-button,
|
||||
.member-approval-actions .member-agree-button {
|
||||
color: #fff;
|
||||
border-color: var(--member-primary);
|
||||
background: var(--member-primary);
|
||||
}
|
||||
|
||||
.member-approval-actions .member-return-button {
|
||||
color: #fff;
|
||||
border-color: #e6a23c;
|
||||
background: #e6a23c;
|
||||
}
|
||||
|
||||
.member-form-skeleton {
|
||||
padding: 0 12px 24px;
|
||||
}
|
||||
|
||||
.member-form-skeleton__card {
|
||||
min-height: 200px;
|
||||
margin-bottom: 10px;
|
||||
padding: 16px 14px;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.member-form-skeleton__card .van-skeleton {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.member-info-sheet {
|
||||
height: 88%;
|
||||
overflow: hidden;
|
||||
border-radius: 16px 16px 0 0;
|
||||
background: var(--member-page-bg);
|
||||
}
|
||||
|
||||
.member-info-sheet .van-action-sheet__header {
|
||||
height: 48px;
|
||||
color: #1f2937;
|
||||
background: #fff;
|
||||
font-size: 16px;
|
||||
line-height: 48px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-info-scroll {
|
||||
height: calc(100% - 48px);
|
||||
padding: 12px 12px calc(82px + env(safe-area-inset-bottom));
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.member-detail-card {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
box-shadow: 0 5px 16px rgba(55, 85, 126, .07);
|
||||
}
|
||||
|
||||
.member-detail-card__title {
|
||||
position: relative;
|
||||
padding: 12px 14px 8px 21px;
|
||||
color: #354255;
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.member-detail-card__title::before {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
bottom: 11px;
|
||||
left: 12px;
|
||||
width: 2px;
|
||||
border-radius: 2px;
|
||||
background: var(--member-primary);
|
||||
content: "";
|
||||
}
|
||||
|
||||
.member-detail-card .van-cell {
|
||||
padding: 10px 14px;
|
||||
color: #4f5d70;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.member-detail-card .van-cell__title {
|
||||
color: #7b899b;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.member-hero__content,
|
||||
.member-page-main,
|
||||
.member-form-skeleton {
|
||||
max-width: 520px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.member-form-actions,
|
||||
.member-approval-actions {
|
||||
right: 50%;
|
||||
left: auto;
|
||||
width: 520px;
|
||||
transform: translateX(50%);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user