feat:职代会h5端UI优化调整

This commit is contained in:
2026-07-31 17:28:32 +08:00
parent c910752e2e
commit 29f305d677
10 changed files with 821 additions and 205 deletions
@@ -37,6 +37,12 @@ public class CongressH5Controller {
public void meetingListPage() {
}
@At("/meeting/remark")
@Ok("beetl:/platform/zhghh5/democratic/congress/meeting/remark.html")
@SaCheckLogin
public void meetingRemarkPage() {
}
@At("/pdf")
@Ok("beetl:/platform/zhghh5/democratic/congress/pdf.html")
@SaCheckLogin
@@ -69,14 +75,38 @@ public class CongressH5Controller {
@At("/materialsList")
@SaCheckLogin
public Result materialsList(@Param("typeId") String typeId, @Param("timeId") String timeId, @Param("emplid") String emplid) {
return Result.success(congressH5Service.materialsList(typeId, timeId, emplid));
public Result materialsList(@Param("typeId") String typeId,
@Param("timeId") String timeId,
@Param("emplid") String emplid,
@Param("searchKeyword") String searchKeyword,
@Param("fileType") String fileType,
@Param("uploadTimeOrder") String uploadTimeOrder,
@Param("pageNumber") Integer pageNumber,
@Param("pageSize") Integer pageSize) {
return Result.success(congressH5Service.materialsList(typeId, timeId, emplid, searchKeyword,
fileType, uploadTimeOrder, pageNumber, pageSize));
}
@At("/user/meetingList")
@SaCheckLogin
public Result userMeetingList(@Param("timeId") String timeId, @Param("emplid") String emplid) {
return Result.success(congressH5Service.userMeetingList(timeId, emplid));
public Result userMeetingList(@Param("timeId") String timeId,
@Param("emplid") String emplid,
@Param("searchKeyword") String searchKeyword,
@Param("signTimeStatus") String signTimeStatus,
@Param("signInCountStatus") String signInCountStatus,
@Param("signStatus") String signStatus,
@Param("pageNumber") Integer pageNumber,
@Param("pageSize") Integer pageSize) {
return Result.success(congressH5Service.userMeetingList(timeId, emplid, searchKeyword,
signTimeStatus, signInCountStatus, signStatus, pageNumber, pageSize));
}
@At("/user/meetingRemark")
@SaCheckLogin
public Result meetingRemark(@Param("meetingId") String meetingId,
@Param("timeId") String timeId,
@Param("emplid") String emplid) {
return Result.success(congressH5Service.meetingRemark(meetingId, timeId, emplid));
}
@At("/signin")
@@ -1,6 +1,7 @@
package com.budwk.app.zhgh.democratic.congress.service;
import com.budwk.app.base.result.Result;
import com.budwk.app.base.page.Pagination;
import org.nutz.lang.util.NutMap;
import java.util.List;
@@ -11,9 +12,14 @@ public interface CongressH5Service {
List<NutMap> materialsTypeList();
List<NutMap> materialsList(String typeId, String sessionId, String emplid);
Pagination<NutMap> materialsList(String typeId, String sessionId, String emplid, String searchKeyword,
String fileType, String uploadTimeOrder, Integer pageNumber, Integer pageSize);
List<NutMap> userMeetingList(String sessionId, String emplid);
Pagination<NutMap> userMeetingList(String sessionId, String emplid, String searchKeyword,
String signTimeStatus, String signInCountStatus, String signStatus,
Integer pageNumber, Integer pageSize);
NutMap meetingRemark(String meetingId, String sessionId, String emplid);
Result signin(String repId, String sessionId, String timeId, String meetingId);
@@ -1,6 +1,7 @@
package com.budwk.app.zhgh.democratic.congress.service.impl;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.result.Result;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.democratic.congress.service.CongressH5Service;
@@ -44,6 +45,7 @@ public class CongressH5ServiceImpl implements CongressH5Service {
AND COALESCE(dg.delFlag, 0) = 0
WHERE d.loginName = @emplid
AND COALESCE(d.delFlag, 0) = 0
AND COALESCE(s.enable, 0) = 1
ORDER BY s.startDate DESC, s.createdAt DESC, s.id DESC
""");
sql.setParam("emplid", loginName);
@@ -90,9 +92,13 @@ public class CongressH5ServiceImpl implements CongressH5Service {
}
@Override
public List<NutMap> materialsList(String typeId, String sessionId, String emplid) {
public Pagination<NutMap> materialsList(String typeId, String sessionId, String emplid, String searchKeyword,
String fileType, String uploadTimeOrder, Integer pageNumber, Integer pageSize) {
String loginName = loginName(emplid);
Sql sql = Sqls.create("""
int currentPage = pageNumber == null || pageNumber < 1 ? 1 : pageNumber;
int currentSize = pageSize == null || pageSize < 1 ? 10 : Math.min(pageSize, 50);
String orderBy = "asc".equalsIgnoreCase(uploadTimeOrder) ? "ASC" : "DESC";
Sql sql = Sqls.create(("""
SELECT
cm.id,
cm.session_id AS sessionId,
@@ -126,19 +132,50 @@ public class CongressH5ServiceImpl implements CongressH5Service {
WHERE COALESCE(cm.deleted, 0) = 0
AND cm.type_id = @typeId
AND (cm.session_id = @sessionId OR cm.time_id = @sessionId)
ORDER BY cm.sort_no ASC, cm.create_time DESC
""");
AND (@searchKeyword = '' OR cm.name LIKE CONCAT('%%', @searchKeyword, '%%')
OR cm.file_name LIKE CONCAT('%%', @searchKeyword, '%%'))
AND (@fileType = '' OR FIND_IN_SET(LOWER(REPLACE(cm.file_type, '.', '')), @fileType) > 0
OR FIND_IN_SET(LOWER(SUBSTRING_INDEX(cm.file_name, '.', -1)), @fileType) > 0)
ORDER BY cm.create_time %s, cm.id DESC
""").formatted(orderBy));
sql.setParam("typeId", typeId);
sql.setParam("sessionId", sessionId);
sql.setParam("emplid", loginName);
sql.setParam("searchKeyword", StrUtil.blankToDefault(searchKeyword, ""));
sql.setParam("fileType", StrUtil.blankToDefault(fileType, ""));
sql.setPager(dao.createPager(currentPage, currentSize));
sql.setCallback(Sqls.callback.maps());
dao.execute(sql);
return sql.getList(NutMap.class);
int totalCount = count("""
SELECT COUNT(DISTINCT cm.id)
FROM congress_materials cm
INNER JOIN teacher_congress_delegate d ON d.sessionId = cm.session_id
AND d.loginName = @emplid
AND COALESCE(d.delFlag, 0) = 0
WHERE COALESCE(cm.deleted, 0) = 0
AND cm.type_id = @typeId
AND (cm.session_id = @sessionId OR cm.time_id = @sessionId)
AND (@searchKeyword = '' OR cm.name LIKE CONCAT('%%', @searchKeyword, '%%')
OR cm.file_name LIKE CONCAT('%%', @searchKeyword, '%%'))
AND (@fileType = '' OR FIND_IN_SET(LOWER(REPLACE(cm.file_type, '.', '')), @fileType) > 0
OR FIND_IN_SET(LOWER(SUBSTRING_INDEX(cm.file_name, '.', -1)), @fileType) > 0)
""", NutMap.NEW()
.addv("typeId", typeId)
.addv("sessionId", sessionId)
.addv("emplid", loginName)
.addv("searchKeyword", StrUtil.blankToDefault(searchKeyword, ""))
.addv("fileType", StrUtil.blankToDefault(fileType, "")));
return new Pagination<>(currentPage, currentSize, totalCount, sql.getList(NutMap.class));
}
@Override
public List<NutMap> userMeetingList(String sessionId, String emplid) {
public Pagination<NutMap> userMeetingList(String sessionId, String emplid, String searchKeyword,
String signTimeStatus, String signInCountStatus, String signStatus,
Integer pageNumber, Integer pageSize) {
String loginName = loginName(emplid);
int currentPage = pageNumber == null || pageNumber < 1 ? 1 : pageNumber;
int currentSize = pageSize == null || pageSize < 1 ? 10 : Math.min(pageSize, 50);
Sql sql = Sqls.create("""
SELECT
m.id,
@@ -166,13 +203,93 @@ public class CongressH5ServiceImpl implements CongressH5Service {
AND si.rep_id = d.id
WHERE COALESCE(m.deleted, 0) = 0
AND (m.session_id = @sessionId OR m.time_id = @sessionId)
AND (@searchKeyword = '' OR m.meeting_name LIKE CONCAT('%', @searchKeyword, '%'))
AND (@signTimeStatus = ''
OR (@signTimeStatus = 'upcoming' AND m.sign_in_start_time > NOW())
OR (@signTimeStatus = 'ongoing' AND m.sign_in_start_time <= NOW() AND m.sign_in_end_time >= NOW())
OR (@signTimeStatus = 'ended' AND m.sign_in_end_time < NOW()))
AND (@signInCountStatus = ''
OR (@signInCountStatus = 'has' AND EXISTS (
SELECT 1 FROM congress_sign_in count_si
WHERE count_si.meeting_id = m.id AND COALESCE(count_si.deleted, 0) = 0))
OR (@signInCountStatus = 'none' AND NOT EXISTS (
SELECT 1 FROM congress_sign_in count_si
WHERE count_si.meeting_id = m.id AND COALESCE(count_si.deleted, 0) = 0)))
AND (@signStatus = ''
OR (@signStatus = 'signed' AND si.id IS NOT NULL)
OR (@signStatus = 'unsigned' AND si.id IS NULL))
ORDER BY m.sign_in_start_time DESC, m.create_time DESC
""");
sql.setParam("sessionId", sessionId);
sql.setParam("emplid", loginName);
sql.setParam("searchKeyword", StrUtil.blankToDefault(searchKeyword, ""));
sql.setParam("signTimeStatus", StrUtil.blankToDefault(signTimeStatus, ""));
sql.setParam("signInCountStatus", StrUtil.blankToDefault(signInCountStatus, ""));
sql.setParam("signStatus", StrUtil.blankToDefault(signStatus, ""));
sql.setPager(dao.createPager(currentPage, currentSize));
sql.setCallback(Sqls.callback.maps());
dao.execute(sql);
return sql.getList(NutMap.class);
int totalCount = count("""
SELECT COUNT(DISTINCT m.id)
FROM congress_sign_in_meeting m
INNER JOIN teacher_congress_delegate d ON d.sessionId = m.session_id
AND d.loginName = @emplid
AND COALESCE(d.delFlag, 0) = 0
LEFT JOIN congress_sign_in si ON m.id = si.meeting_id
AND COALESCE(si.deleted, 0) = 0
AND si.rep_id = d.id
WHERE COALESCE(m.deleted, 0) = 0
AND (m.session_id = @sessionId OR m.time_id = @sessionId)
AND (@searchKeyword = '' OR m.meeting_name LIKE CONCAT('%', @searchKeyword, '%'))
AND (@signTimeStatus = ''
OR (@signTimeStatus = 'upcoming' AND m.sign_in_start_time > NOW())
OR (@signTimeStatus = 'ongoing' AND m.sign_in_start_time <= NOW() AND m.sign_in_end_time >= NOW())
OR (@signTimeStatus = 'ended' AND m.sign_in_end_time < NOW()))
AND (@signInCountStatus = ''
OR (@signInCountStatus = 'has' AND EXISTS (
SELECT 1 FROM congress_sign_in count_si
WHERE count_si.meeting_id = m.id AND COALESCE(count_si.deleted, 0) = 0))
OR (@signInCountStatus = 'none' AND NOT EXISTS (
SELECT 1 FROM congress_sign_in count_si
WHERE count_si.meeting_id = m.id AND COALESCE(count_si.deleted, 0) = 0)))
AND (@signStatus = ''
OR (@signStatus = 'signed' AND si.id IS NOT NULL)
OR (@signStatus = 'unsigned' AND si.id IS NULL))
""", NutMap.NEW()
.addv("sessionId", sessionId)
.addv("emplid", loginName)
.addv("searchKeyword", StrUtil.blankToDefault(searchKeyword, ""))
.addv("signTimeStatus", StrUtil.blankToDefault(signTimeStatus, ""))
.addv("signInCountStatus", StrUtil.blankToDefault(signInCountStatus, ""))
.addv("signStatus", StrUtil.blankToDefault(signStatus, "")));
return new Pagination<>(currentPage, currentSize, totalCount, sql.getList(NutMap.class));
}
@Override
public NutMap meetingRemark(String meetingId, String sessionId, String emplid) {
Sql sql = Sqls.create("""
SELECT
m.id,
m.meeting_name AS meetingName,
m.remark,
m.session_id AS sessionId,
COALESCE(m.time_id, m.session_id) AS timeId
FROM congress_sign_in_meeting m
INNER JOIN teacher_congress_delegate d ON d.sessionId = m.session_id
AND d.loginName = @emplid
AND COALESCE(d.delFlag, 0) = 0
WHERE m.id = @meetingId
AND COALESCE(m.deleted, 0) = 0
AND (m.session_id = @sessionId OR m.time_id = @sessionId)
LIMIT 1
""");
sql.setParam("meetingId", meetingId);
sql.setParam("sessionId", sessionId);
sql.setParam("emplid", loginName(emplid));
sql.setCallback(Sqls.callback.map());
dao.execute(sql);
return sql.getObject(NutMap.class);
}
@Override
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

@@ -15,12 +15,11 @@ layout("/layouts/platform_h5.html"){
<div class="page-header">
<div class="session-info-card">
<h2 class="session-title">{{ selectedSessionName }}</h2>
<!-- <p class="session-subtitle">{{ selectedTimeText }}</p>-->
<button v-if="timesList.length > 1" type="button" class="header-switch-btn" @click="showTimePicker = true">
<span>切换届次</span>
<van-icon name="arrow-down" size="12"></van-icon>
</button>
</div>
<button v-if="timesList.length > 1" type="button" class="header-switch-btn" @click="showTimePicker = true">
<span>切换届次</span>
<van-icon name="arrow-down" size="12"></van-icon>
</button>
</div>
<div class="module-list-container">
@@ -29,6 +28,7 @@ layout("/layouts/platform_h5.html"){
v-for="module in moduleList"
:key="module.id"
class="module-card"
:class="resolveTheme(module.name)"
@click="handleModuleClick(module)"
>
<div class="module-header">
@@ -47,7 +47,7 @@ layout("/layouts/platform_h5.html"){
</template>
<van-popup v-model="showTimePicker" position="bottom">
<van-popup v-model="showTimePicker" position="bottom" :z-index="3000">
<van-picker
show-toolbar
:columns="formattedTimeColumns"
@@ -128,7 +128,7 @@ layout("/layouts/platform_h5.html"){
this.moduleList = hasSignin ? modules : [{
id: "signin",
name: "会议签到",
icon: "calendar-o",
icon: "completed",
desc: "点击进行会议签到"
}].concat(modules)
},
@@ -186,13 +186,13 @@ layout("/layouts/platform_h5.html"){
},
resolveIcon(name) {
if (!name) return "orders-o"
if (name.indexOf("会议签到") > -1) return "calendar-o"
if (name.indexOf("会议签到") > -1) return "completed"
if (name.indexOf("评议") > -1) return "star"
if (name.indexOf("议题") > -1) return "todo-list-o"
if (name.indexOf("资料") > -1) return "notes-o"
if (name.indexOf("公告") > -1 || name.indexOf("结果") > -1) return "bullhorn-o"
if (name.indexOf("议题") > -1) return "todo-list"
if (name.indexOf("资料") > -1) return "notes"
if (name.indexOf("公告") > -1 || name.indexOf("结果") > -1) return "bell"
if (name.indexOf("文件") > -1) return "description"
return "orders-o"
return "orders"
},
resolveDesc(name) {
if (!name) return ""
@@ -203,6 +203,15 @@ layout("/layouts/platform_h5.html"){
if (name.indexOf("表决公告") > -1) return "查看表决结果公告"
if (name.indexOf("资料") > -1) return "查看会议准备资料"
return ""
},
resolveTheme(name) {
if (!name) return "theme-blue"
if (name.indexOf("会议签到") > -1) return "theme-blue"
if (name.indexOf("文件") > -1) return "theme-blue"
if (name.indexOf("表决公告") > -1) return "theme-green"
if (name.indexOf("议题") > -1) return "theme-purple"
if (name.indexOf("评议") > -1) return "theme-orange module-card-wide"
return "theme-blue"
}
},
created() {
@@ -213,60 +222,62 @@ layout("/layouts/platform_h5.html"){
<style id="style-congress-h5">
.congress-page {
min-height: calc(100vh - 46px);
background: #f5f7fa;
height: calc(100vh - 46px);
background: #f4f8ff;
overflow: hidden;
display: flex;
flex-direction: column;
}
.page-header {
background: linear-gradient(135deg, #1989fa 0%, #0d6efd 100%);
padding: 34px 16px 28px;
min-height: 192px;
background: #1686ff url("${base!}/images/congress/h5-congress-header.png") center center / cover no-repeat;
padding: 0px 15px 50px;
color: #fff;
box-shadow: 0 4px 16px rgba(25, 137, 250, 0.15);
box-shadow: 0 12px 28px rgba(25, 137, 250, 0.18);
display: flex;
justify-content: center;
justify-content: flex-start;
align-items: center;
position: relative;
overflow: hidden;
flex-shrink: 0;
}
.session-info-card {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
align-items: flex-start;
text-align: left;
position: relative;
z-index: 3;
max-width: 50%;
}
.session-title {
font-size: 20px;
font-weight: 600;
line-height: 1.4;
font-size: 25px;
font-weight: 700;
line-height: 1.25;
color: #fff;
margin: 0 0 8px;
}
.session-subtitle {
font-size: 15px;
line-height: 1.3;
color: #fff;
margin: 0;
margin: 0 0 10px;
text-shadow: 0 4px 12px rgba(3, 77, 168, 0.18);
}
.header-switch-btn {
position: absolute;
top: 10px;
right: 12px;
height: 28px;
padding: 0 10px;
margin-top: 6px;
height: 34px;
padding: 0 14px;
border: 0;
border-radius: 14px;
border-radius: 18px;
background: rgba(255, 255, 255, 0.18);
color: #fff;
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 12px;
gap: 6px;
font-size: 14px;
font-weight: 600;
line-height: 1;
cursor: pointer;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.22);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.36), 0 8px 18px rgba(0, 66, 160, 0.12);
backdrop-filter: blur(8px);
}
@@ -276,70 +287,62 @@ layout("/layouts/platform_h5.html"){
}
.module-list-container {
padding: 16px;
position: relative;
z-index: 2;
flex: 1;
min-height: 0;
margin: -72px 0 0;
padding: 18px 16px 24px;
background: #fff;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.modules-wrapper {
display: flex;
flex-direction: column;
gap: 14px;
display: grid;
grid-template-columns: minmax(0, 1fr);
gap: 12px;
}
.module-card {
background: #fff;
border-radius: 16px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
min-height: 98px;
background: linear-gradient(135deg, #f8fbff 0%, #fff 100%);
border-radius: 14px;
box-shadow: 0 8px 18px rgba(27, 56, 105, 0.06);
overflow: hidden;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid rgba(0, 0, 0, 0.03);
border: 1px solid rgba(237, 242, 250, 0.88);
position: relative;
}
.module-card::before {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 4px;
background: linear-gradient(180deg, #1989fa 0%, #0d6efd 100%);
opacity: 0;
transition: opacity 0.3s ease;
}
.module-card:hover {
box-shadow: 0 8px 24px rgba(25, 137, 250, 0.12);
transform: translateY(-3px);
border-color: rgba(25, 137, 250, 0.1);
}
.module-card:hover::before {
opacity: 1;
.module-card-wide {
grid-column: auto;
}
.module-card:active {
transform: translateY(-1px) scale(0.99);
transform: scale(0.99);
box-shadow: 0 4px 16px rgba(25, 137, 250, 0.08);
}
.module-header {
padding: 16px 18px;
min-height: 60px;
padding: 14px;
display: flex;
align-items: center;
gap: 14px;
gap: 12px;
}
.icon-wrapper {
width: 56px;
height: 56px;
border-radius: 14px;
width: 54px;
height: 54px;
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #e6f0ff 0%, #f0f5ff 100%);
background: #eef5ff;
flex-shrink: 0;
box-shadow: 0 2px 8px rgba(25, 137, 250, 0.12);
box-shadow: 0 8px 18px rgba(25, 137, 250, 0.1);
color: #1989fa;
}
@@ -349,9 +352,9 @@ layout("/layouts/platform_h5.html"){
}
.module-title {
font-size: 17px;
font-weight: 600;
color: #4a4a4a;
font-size: 16px;
font-weight: 700;
color: #111a3a;
margin: 0 0 6px;
line-height: 1.4;
overflow: hidden;
@@ -360,8 +363,8 @@ layout("/layouts/platform_h5.html"){
}
.module-desc {
font-size: 13px;
color: #969799;
font-size: 12px;
color: #7d89a6;
margin: 0;
line-height: 1.5;
overflow: hidden;
@@ -370,15 +373,62 @@ layout("/layouts/platform_h5.html"){
}
.arrow-icon {
font-size: 18px;
color: #c8c9cc;
width: 26px;
height: 26px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
color: #1989fa;
background: rgba(25, 137, 250, 0.1);
flex-shrink: 0;
transition: all 0.3s ease;
}
.module-card:hover .arrow-icon {
color: #1989fa;
transform: translateX(4px);
.theme-green {
background: linear-gradient(135deg, #f3fff9 0%, #fff 100%);
}
.theme-green .icon-wrapper {
color: #17c979;
background: #eafbf2;
box-shadow: 0 8px 18px rgba(23, 201, 121, 0.12);
}
.theme-green .arrow-icon {
color: #17b977;
background: rgba(23, 201, 121, 0.12);
}
.theme-purple {
background: linear-gradient(135deg, #fbf7ff 0%, #fff 100%);
}
.theme-purple .icon-wrapper {
color: #8756e9;
background: #f1eaff;
box-shadow: 0 8px 18px rgba(135, 86, 233, 0.12);
}
.theme-purple .arrow-icon {
color: #8756e9;
background: rgba(135, 86, 233, 0.12);
}
.theme-orange {
background: linear-gradient(135deg, #fff8ed 0%, #fff 100%);
}
.theme-orange .icon-wrapper {
color: #ff9f1a;
background: #fff2df;
box-shadow: 0 8px 18px rgba(255, 159, 26, 0.12);
}
.theme-orange .arrow-icon {
color: #d9a05b;
background: rgba(255, 159, 26, 0.12);
}
.empty-box {
@@ -6,14 +6,18 @@ layout("/layouts/platform_h5.html"){
<van-nav-bar :title="pageTitle" left-text="返回" left-arrow @click-left="backToCongress" placeholder fixed></van-nav-bar>
<div class="file-list-page">
<van-sticky :offset-top="46">
<div class="file-filter-bar">
<van-search v-model="keyword" placeholder="搜索文件名" shape="round" class="file-search" @input="onKeywordChange"></van-search>
<van-dropdown-menu class="file-filter-menu">
<van-dropdown-item v-model="selectedFileType" :options="fileTypeOptions" @change="resetList"></van-dropdown-item>
<van-dropdown-item v-model="uploadTimeOrder" :options="uploadTimeSortOptions" @change="resetList"></van-dropdown-item>
</van-dropdown-menu>
</div>
</van-sticky>
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<van-list v-model="loading" :finished="finished" :finished-text="fileList.length > 0 ? '没有更多了' : ''" @load="onLoad">
<div v-for="item in fileList" :key="item.id" class="file-card" @click="handleFileClick(item)">
<div v-if="item.hasVoted !== null && item.hasVoted !== undefined" class="vote-badge">
<span v-if="isVoted(item.hasVoted)" class="badge voted">已投票</span>
<span v-else class="badge pending">待投票</span>
</div>
<div class="card-left">
<div class="icon-wrapper">
<img :src="getFileIconUrl(item)" :alt="resolveFileSuffix(item) || 'file'" class="file-type-icon">
@@ -22,17 +26,27 @@ layout("/layouts/platform_h5.html"){
<div class="card-content">
<div class="card-header">
<span class="file-name">{{ formatFileName(item.name || item.fileName) }}</span>
<van-icon name="arrow" class="arrow-icon"></van-icon>
<div class="card-actions">
<span v-if="item.hasVoted !== null && item.hasVoted !== undefined" class="vote-status" :class="isVoted(item.hasVoted) ? 'voted' : 'pending'">
<van-icon :name="isVoted(item.hasVoted) ? 'checked' : 'clock-o'" size="12"></van-icon>
{{ isVoted(item.hasVoted) ? '已投票' : '待投票' }}
</span>
<van-icon name="arrow" class="arrow-icon"></van-icon>
</div>
</div>
<div v-if="item.uploadTime" class="file-info">
<div class="file-info">
<div class="info-row">
<van-icon name="clock-o" size="14" color="#969799"></van-icon>
<van-icon name="description" size="14"></van-icon>
<span class="info-text">文件类型:<span class="info-value">{{ fileTypeText(item) }}</span></span>
</div>
<div v-if="item.uploadTime" class="info-row">
<van-icon name="clock-o" size="14"></van-icon>
<span class="info-text">上传时间:<span class="info-value">{{ formatTime(item.uploadTime) }}</span></span>
</div>
</div>
</div>
</div>
<van-empty v-if="!loading && fileList.length === 0" description="暂无文件"></van-empty>
<van-empty v-if="!loading && fileList.length === 0" :description="hasFilter ? '未找到匹配文件' : '暂无文件'"></van-empty>
</van-list>
</van-pull-refresh>
</div>
@@ -52,7 +66,39 @@ layout("/layouts/platform_h5.html"){
loadedOnce: false,
typeId: "",
timeId: "",
sessionId: ""
sessionId: "",
keyword: "",
selectedFileType: "",
uploadTimeOrder: "desc",
searchTimer: null,
queryVersion: 0,
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0
}
}
},
computed: {
fileTypeOptions() {
return [
{text: "全部类型", value: ""},
{text: "PDF", value: "pdf"},
{text: "Word", value: "doc,docx"},
{text: "Excel", value: "xls,xlsx"},
{text: "PPT", value: "ppt,pptx"},
{text: "图片", value: "jpg,jpeg,png,gif,bmp,webp"},
{text: "压缩包", value: "zip,rar"}
]
},
uploadTimeSortOptions() {
return [
{text: "上传时间:最新", value: "desc"},
{text: "上传时间:最早", value: "asc"}
]
},
hasFilter() {
return !!(this.keyword || this.selectedFileType)
}
},
methods: {
@@ -72,33 +118,61 @@ layout("/layouts/platform_h5.html"){
return user.loginname || user.loginName || ""
},
onRefresh() {
this.resetList()
},
onLoad() {
if (!this.finished) {
this.fetchFileList()
}
},
onKeywordChange() {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => this.resetList(), 300)
},
resetList() {
this.queryVersion++
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.fileList = []
this.finished = false
this.loadedOnce = false
this.fetchFileList()
},
onLoad() {
if (!this.loadedOnce) {
this.fetchFileList()
}
},
fetchFileList() {
const queryVersion = this.queryVersion
this.loading = true
this.$axios.get("/platform/h5/congress/materialsList", {
params: {
typeId: this.typeId,
timeId: this.timeId,
emplid: this.loginName()
emplid: this.loginName(),
searchKeyword: this.keyword,
fileType: this.selectedFileType,
uploadTimeOrder: this.uploadTimeOrder,
pageNumber: this.pageForm.pageNumber,
pageSize: this.pageForm.pageSize
}
}).then((res) => {
if (queryVersion !== this.queryVersion) return
if (res.code === 0) {
this.fileList = res.data || []
const pageData = res.data || {}
const records = pageData.list || []
this.fileList = this.fileList.concat(records)
this.pageForm.totalCount = pageData.totalCount || 0
if (this.fileList.length >= this.pageForm.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
} else {
this.finished = true
}
this.finished = true
this.loadedOnce = true
}).finally(() => {
this.loading = false
this.refreshing = false
if (queryVersion === this.queryVersion) {
this.loading = false
this.refreshing = false
}
})
},
getFileIconUrl(item) {
@@ -135,6 +209,10 @@ layout("/layouts/platform_h5.html"){
isKnownSuffix(suffix) {
return ["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "zip", "rar", "jpg", "jpeg", "png", "gif", "bmp", "webp", "mp4", "avi", "wmv", "rmvb", "flv", "mkv", "mp3", "wav", "wma", "flac", "ape"].indexOf(suffix) > -1
},
fileTypeText(item) {
const suffix = this.resolveFileSuffix(item)
return suffix ? suffix.toUpperCase() : "未知类型"
},
formatTime(time) {
if (!time) return ""
const date = new Date(time)
@@ -193,6 +271,27 @@ layout("/layouts/platform_h5.html"){
padding-top: 1px;
}
.file-filter-bar {
background: #fff;
box-shadow: 0 2px 8px rgba(30, 48, 80, 0.04);
}
.file-search {
padding: 10px 16px 6px;
background: transparent;
}
.file-filter-menu {
height: 42px;
box-shadow: none;
}
.file-filter-menu .van-dropdown-menu__bar {
height: 42px;
box-shadow: none;
border-top: 1px solid #f2f3f5;
}
.file-card {
background: #fff;
margin: 12px 16px;
@@ -220,48 +319,43 @@ layout("/layouts/platform_h5.html"){
transition: opacity 0.3s ease;
}
.file-card:hover {
box-shadow: 0 8px 24px rgba(25, 137, 250, 0.12);
transform: translateY(-3px);
border-color: rgba(25, 137, 250, 0.1);
}
.file-card:hover::before {
opacity: 1;
}
.file-card:active {
transform: translateY(-1px) scale(0.99);
transform: scale(0.99);
box-shadow: 0 4px 16px rgba(25, 137, 250, 0.08);
}
.vote-badge {
position: absolute;
top: 0;
left: 0;
z-index: 1;
.card-actions {
display: inline-flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
.badge {
display: inline-block;
padding: 6px 14px;
.vote-status {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 4px 7px;
font-size: 12px;
font-weight: 600;
border-bottom-right-radius: 12px;
color: #fff;
line-height: 1;
border-radius: 10px;
}
.badge.voted {
background: linear-gradient(135deg, #52c41a 0%, #389e0d 100%);
.vote-status.voted {
color: #17a65b;
background: #edf9f1;
}
.badge.pending {
background: linear-gradient(135deg, #faad14 0%, #d48806 100%);
.vote-status.pending {
color: #d98a00;
background: #fff6e5;
}
.card-left {
flex-shrink: 0;
margin-top: 12px;
display: flex;
align-items: center;
}
.icon-wrapper {
@@ -316,6 +410,15 @@ layout("/layouts/platform_h5.html"){
gap: 6px;
font-size: 13px;
color: #969799;
line-height: 1.5;
}
.info-row + .info-row {
margin-top: 4px;
}
.info-row .van-icon {
color: #969799;
}
.info-value {
@@ -6,27 +6,42 @@ layout("/layouts/platform_h5.html"){
<van-nav-bar title="会议签到" left-text="返回" left-arrow @click-left="backToCongress" placeholder fixed></van-nav-bar>
<div class="meeting-list-page">
<van-sticky :offset-top="46">
<div class="meeting-filter-bar">
<van-search v-model="keyword" placeholder="搜索会议名称" shape="round" class="meeting-search" @input="onKeywordChange"></van-search>
<van-dropdown-menu class="meeting-filter-menu">
<van-dropdown-item v-model="signTimeStatus" :options="signTimeOptions" @change="resetList"></van-dropdown-item>
<van-dropdown-item v-model="signInCountStatus" :options="signInCountOptions" @change="resetList"></van-dropdown-item>
<van-dropdown-item v-model="signStatus" :options="signStatusOptions" @change="resetList"></van-dropdown-item>
</van-dropdown-menu>
</div>
</van-sticky>
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<van-list v-model="loading" :finished="finished" :finished-text="meetingList.length > 0 ? '没有更多了' : ''" @load="onLoad">
<div v-for="item in meetingList" :key="item.id" class="meeting-card">
<div class="card-left">
<div class="icon-wrapper" :class="{'signed-icon': item.signInId}">
<van-icon name="calendar-o" size="26"></van-icon>
</div>
</div>
<div v-for="item in meetingList" :key="item.id" class="meeting-card" :class="{'meeting-card-disabled': !item.signInId && !canSignIn(item)}">
<div class="card-content">
<div class="card-header">
<div class="card-left">
<div class="icon-wrapper" :class="{'signed-icon': item.signInId}">
<van-icon name="completed" size="26"></van-icon>
</div>
</div>
<span class="meeting-name">{{ item.meetingName }}</span>
<button v-if="item.remark" type="button" class="remark-link" @click.stop="openRemark(item)">
<van-icon name="notes-o" size="14"></van-icon>
<span>备注</span>
<van-icon name="arrow" size="12"></van-icon>
</button>
</div>
<div class="info-list">
<div v-if="item.signInStartTime" class="info-row">
<van-icon name="clock-o" size="14" color="#969799"></van-icon>
<span class="info-text">签到时间<span class="info-value">{{ formatTimeRange(item.signInStartTime, item.signInEndTime) }}</span></span>
<span class="info-text">签到开始<span class="info-value">{{ formatTime(item.signInStartTime) }}</span></span>
</div>
<div v-if="item.userSignInTime" class="info-row signed">
<van-icon name="checked" size="14" color="#07c160"></van-icon>
<span class="info-text">签到:<span class="info-value">{{ formatTime(item.userSignInTime) }}</span></span>
<div v-if="item.signInEndTime" class="info-row">
<van-icon name="clock-o" size="14" color="#969799"></van-icon>
<span class="info-text">签到结束<span class="info-value">{{ formatTime(item.signInEndTime) }}</span></span>
</div>
<div class="info-row count">
<van-icon name="friends-o" size="14" color="#1989fa"></van-icon>
@@ -34,11 +49,15 @@ layout("/layouts/platform_h5.html"){
</div>
</div>
<div v-if="!item.signInId" class="action-section">
<van-button v-if="!canSignIn(item)" disabled type="default" class="signin-btn disabled">
<div v-if="item.userSignInTime" class="action-section signin-status signed-status">
<van-icon name="checked" size="16"></van-icon>
<span>已签到:{{ formatTime(item.userSignInTime) }}</span>
</div>
<div v-else class="action-section">
<div v-if="!canSignIn(item)" class="signin-status disabled-status">
<van-icon name="clock-o" size="16"></van-icon>
{{ getSignInButtonText(item) }}
</van-button>
</div>
<van-button v-else type="primary" class="signin-btn" @click.stop="handleSignInClick(item)">
<van-icon name="checked" size="16"></van-icon>
立即签到
@@ -46,7 +65,7 @@ layout("/layouts/platform_h5.html"){
</div>
</div>
</div>
<van-empty v-if="!loading && meetingList.length === 0" description="暂无会议"></van-empty>
<van-empty v-if="!loading && meetingList.length === 0" :description="hasFilter ? '未找到匹配会议' : '暂无会议'"></van-empty>
</van-list>
</van-pull-refresh>
</div>
@@ -64,7 +83,45 @@ layout("/layouts/platform_h5.html"){
refreshing: false,
loadedOnce: false,
timeId: "",
sessionId: ""
sessionId: "",
keyword: "",
signTimeStatus: "",
signInCountStatus: "",
signStatus: "",
searchTimer: null,
queryVersion: 0,
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0
}
}
},
computed: {
signTimeOptions() {
return [
{text: "签到时间", value: ""},
{text: "未开始", value: "upcoming"},
{text: "进行中", value: "ongoing"},
{text: "已结束", value: "ended"}
]
},
signInCountOptions() {
return [
{text: "签到人数", value: ""},
{text: "有人签到", value: "has"},
{text: "无人签到", value: "none"}
]
},
signStatusOptions() {
return [
{text: "签到状态", value: ""},
{text: "已签到", value: "signed"},
{text: "未签到", value: "unsigned"}
]
},
hasFilter() {
return !!(this.keyword || this.signTimeStatus || this.signInCountStatus || this.signStatus)
}
},
methods: {
@@ -82,31 +139,68 @@ layout("/layouts/platform_h5.html"){
return user.loginname || user.loginName || ""
},
onRefresh() {
this.resetList()
},
onLoad() {
if (!this.finished) {
this.fetchMeetingList()
}
},
onKeywordChange() {
clearTimeout(this.searchTimer)
this.searchTimer = setTimeout(() => this.resetList(), 300)
},
resetList() {
this.queryVersion++
this.pageForm.pageNumber = 1
this.pageForm.totalCount = 0
this.meetingList = []
this.finished = false
this.loadedOnce = false
this.fetchMeetingList()
},
onLoad() {
if (!this.loadedOnce) {
this.fetchMeetingList()
}
},
fetchMeetingList() {
const queryVersion = this.queryVersion
this.loading = true
this.$axios.get("/platform/h5/congress/user/meetingList", {
params: {timeId: this.timeId, emplid: this.loginName()}
params: {
timeId: this.timeId,
emplid: this.loginName(),
searchKeyword: this.keyword,
signTimeStatus: this.signTimeStatus,
signInCountStatus: this.signInCountStatus,
signStatus: this.signStatus,
pageNumber: this.pageForm.pageNumber,
pageSize: this.pageForm.pageSize
}
}).then((res) => {
if (queryVersion !== this.queryVersion) return
if (res.code === 0) {
this.meetingList = res.data || []
const pageData = res.data || {}
const records = pageData.list || []
this.meetingList = this.meetingList.concat(records)
this.pageForm.totalCount = pageData.totalCount || 0
if (this.meetingList.length >= this.pageForm.totalCount) {
this.finished = true
} else {
this.pageForm.pageNumber++
}
} else {
this.finished = true
}
this.finished = true
this.loadedOnce = true
}).finally(() => {
this.loading = false
this.refreshing = false
if (queryVersion === this.queryVersion) {
this.loading = false
this.refreshing = false
}
})
},
openRemark(item) {
this.$pjaxReplace("/platform/h5/congress/meeting/remark?meetingId=" + encodeURIComponent(item.id) +
"&timeId=" + encodeURIComponent(item.timeId || this.timeId) +
"&sessionId=" + encodeURIComponent(item.sessionId || this.sessionId))
},
handleSignInClick(item) {
if (item.signInId) {
this.$toast.success("您已签到,无需重复签到")
@@ -153,7 +247,7 @@ layout("/layouts/platform_h5.html"){
const end = new Date(item.signInEndTime).getTime()
if (Number.isNaN(start) || Number.isNaN(end)) return "立即签到"
if (now < start) return "未到签到时间"
if (now > end) return "已过签到时间"
if (now > end) return "已过签到时间"
return "立即签到"
},
formatTimeRange(startTime, endTime) {
@@ -183,16 +277,38 @@ layout("/layouts/platform_h5.html"){
padding-top: 1px;
}
.meeting-filter-bar {
background: #fff;
box-shadow: 0 2px 8px rgba(30, 48, 80, 0.04);
}
.meeting-search {
padding: 10px 16px 6px;
background: transparent;
}
.meeting-filter-menu {
height: 42px;
box-shadow: none;
}
.meeting-filter-menu .van-dropdown-menu__bar {
height: 42px;
box-shadow: none;
border-top: 1px solid #f2f3f5;
}
.meeting-card {
background: #fff;
margin: 16px;
height: 220px;
padding: 24px;
box-sizing: border-box;
border-radius: 18px;
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.06);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
align-items: flex-start;
gap: 18px;
align-items: stretch;
position: relative;
overflow: hidden;
border: 1px solid rgba(0, 0, 0, 0.03);
@@ -210,19 +326,9 @@ layout("/layouts/platform_h5.html"){
transition: opacity 0.3s ease;
}
.meeting-card:hover {
box-shadow: 0 8px 24px rgba(25, 137, 250, 0.12);
transform: translateY(-3px);
border-color: rgba(25, 137, 250, 0.1);
}
.meeting-card:hover::before {
opacity: 1;
}
.card-left {
flex-shrink: 0;
padding-top: 2px;
padding-top: 0;
}
.icon-wrapper {
@@ -242,13 +348,24 @@ layout("/layouts/platform_h5.html"){
color: #fff;
}
.meeting-card-disabled .icon-wrapper {
background: #f4f4f5;
color: #c8c9cc;
box-shadow: none;
}
.card-content {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
}
.card-header {
margin-bottom: 12px;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 12px;
}
.meeting-name {
@@ -256,14 +373,32 @@ layout("/layouts/platform_h5.html"){
color: #323233;
font-weight: 600;
line-height: 1.5;
word-break: break-word;
flex: 1;
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.remark-link {
display: inline-flex;
align-items: center;
gap: 2px;
margin-left: 8px;
padding: 0;
border: 0;
background: transparent;
color: #969799;
font-size: 13px;
line-height: 1.5;
flex-shrink: 0;
}
.info-list {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 12px;
gap: 10px;
margin-bottom: 0;
}
.info-row {
@@ -280,12 +415,36 @@ layout("/layouts/platform_h5.html"){
word-break: break-word;
}
.info-row.signed .info-text {
.info-row.count .info-text {
color: #1989fa;
}
.meeting-card-disabled .info-row.count .van-icon {
color: #c8c9cc !important;
}
.meeting-card-disabled .info-row.count .info-text {
color: #c8c9cc;
}
.action-section {
margin-top: auto;
}
.signin-status {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
line-height: 1.4;
}
.signed-status {
color: #07c160;
}
.info-row.count .info-text {
color: #1989fa;
.disabled-status {
color: #c8c9cc;
}
.signin-btn {
@@ -297,14 +456,9 @@ layout("/layouts/platform_h5.html"){
background: linear-gradient(135deg, #1989fa 0%, #0d6efd 100%);
border: none;
box-shadow: 0 3px 10px rgba(25, 137, 250, 0.3);
transform: translateY(4px);
}
.signin-btn.disabled {
background: linear-gradient(135deg, rgba(25, 137, 250, 0.3) 0%, rgba(13, 110, 253, 0.3) 100%);
color: #fff;
border: 1px solid rgba(25, 137, 250, 0.4);
opacity: 0.7;
}
</style>
<!--#
@@ -0,0 +1,104 @@
<!--#
layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar title="会议备注" left-text="返回" left-arrow @click-left="backToMeeting" placeholder fixed></van-nav-bar>
<div class="meeting-remark-page">
<div v-if="remarkData" class="remark-content-card">
<h2 class="remark-title">{{ remarkData.meetingName }}</h2>
<div class="remark-divider"></div>
<div class="remark-content">{{ remarkData.remark || "暂无备注" }}</div>
</div>
<van-empty v-else-if="!loading" description="暂无备注"></van-empty>
</div>
</div>
<script nonce="${cspNonce!}">
new Vue({
el: "#app",
store,
data() {
return {
loading: true,
meetingId: "",
timeId: "",
sessionId: "",
remarkData: null
}
},
methods: {
initQuery() {
const params = new URLSearchParams(window.location.search)
this.meetingId = params.get("meetingId") || ""
this.timeId = params.get("timeId") || ""
this.sessionId = params.get("sessionId") || this.timeId
},
backToMeeting() {
this.$pjaxReplace("/platform/h5/congress/meeting/list?timeId=" + encodeURIComponent(this.timeId) +
"&sessionId=" + encodeURIComponent(this.sessionId))
},
loginName() {
const user = (this.$store.state && this.$store.state.user) || JSON.parse(window.sessionStorage.getItem("user") || "{}")
return user.loginname || user.loginName || ""
},
fetchRemark() {
this.$axios.get("/platform/h5/congress/user/meetingRemark", {
params: {meetingId: this.meetingId, timeId: this.timeId, emplid: this.loginName()}
}).then((res) => {
if (res.code === 0) {
this.remarkData = res.data || null
}
}).finally(() => {
this.loading = false
})
}
},
created() {
this.initQuery()
this.fetchRemark()
}
})
</script>
<style id="style-congress-meeting-remark-h5">
.meeting-remark-page {
min-height: calc(100vh - 46px);
padding: 16px;
box-sizing: border-box;
background: #f5f7fa;
}
.remark-content-card {
padding: 20px;
border-radius: 14px;
background: #fff;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}
.remark-title {
margin: 0;
color: #323233;
font-size: 17px;
line-height: 1.5;
}
.remark-divider {
height: 1px;
margin: 16px 0;
background: #ebedf0;
}
.remark-content {
color: #646566;
font-size: 15px;
line-height: 1.8;
white-space: pre-wrap;
word-break: break-word;
}
</style>
<!--#
}
#-->
@@ -3,7 +3,7 @@ layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar :title="voteInfo.name || '投票'" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<van-nav-bar title="进行投票" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<div class="vote-page">
<div class="vote-content">
@@ -12,10 +12,10 @@ layout("/layouts/platform_h5.html"){
<div v-if="voteTicketName" class="vote-type-text">{{ voteTicketName }}</div>
<div class="vote-meta">
<div class="meta-item">
<van-icon name="calendar-o" size="14"></van-icon>
<van-icon name="completed" size="14"></van-icon>
<span>{{ sessionName }}</span>
</div>
<div class="meta-divider"></div>
<!-- <div class="meta-divider"></div>-->
<!-- <div class="meta-item">-->
<!-- <van-icon name="clock-o" size="14"></van-icon>-->
<!-- <span>{{ timeName }}</span>-->
@@ -245,6 +245,7 @@ layout("/layouts/platform_h5.html"){
.vote-meta {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding-top: 8px;
border-top: 1px solid #ebedf0;
@@ -372,7 +373,6 @@ layout("/layouts/platform_h5.html"){
.vote-description {
padding: 20px;
border-left: 4px solid #1989fa;
}
.description-header {
@@ -412,6 +412,32 @@ layout("/layouts/platform_h5.html"){
border: 0;
box-shadow: 0 4px 12px rgba(25, 137, 250, 0.3);
}
.vote-table-container {
border-color: #dfe5ee;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(30, 48, 80, 0.04);
}
.vote-table {
border-collapse: separate;
border-spacing: 0;
table-layout: fixed;
}
.vote-table th,
.vote-table td {
border: 0;
border-right: 1px solid #dfe5ee;
border-bottom: 1px solid #dfe5ee;
}
.vote-table tr > :last-child {
border-right: 0;
}
.vote-table tbody tr:last-child td {
border-bottom: 0;
}
</style>
<!--#
@@ -3,7 +3,7 @@ layout("/layouts/platform_h5.html"){
#-->
<div id="app" v-cloak>
<van-nav-bar :title="voteInfo.name || '查看投票'" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<van-nav-bar title="查看投票" left-text="返回" left-arrow @click-left="historyBack" placeholder fixed></van-nav-bar>
<div class="vote-page">
<div class="vote-content">
@@ -12,10 +12,10 @@ layout("/layouts/platform_h5.html"){
<div v-if="voteTicketName" class="vote-type-text">{{ voteTicketName }}</div>
<div class="vote-meta">
<div class="meta-item">
<van-icon name="calendar-o" size="14"></van-icon>
<van-icon name="completed" size="14"></van-icon>
<span>{{ sessionName }}</span>
</div>
<div class="meta-divider"></div>
<!-- <div class="meta-divider"></div>-->
<!-- <div class="meta-item">-->
<!-- <van-icon name="clock-o" size="14"></van-icon>-->
<!-- <span>{{ timeName }}</span>-->
@@ -229,6 +229,7 @@ layout("/layouts/platform_h5.html"){
.vote-meta {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding-top: 8px;
border-top: 1px solid #ebedf0;
@@ -357,7 +358,6 @@ layout("/layouts/platform_h5.html"){
.vote-description {
padding: 20px;
border-left: 4px solid #1989fa;
}
.description-header {
@@ -402,6 +402,32 @@ layout("/layouts/platform_h5.html"){
border: 0;
opacity: 1;
}
.vote-table-container {
border-color: #dfe5ee;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(30, 48, 80, 0.04);
}
.vote-table {
border-collapse: separate;
border-spacing: 0;
table-layout: fixed;
}
.vote-table th,
.vote-table td {
border: 0;
border-right: 1px solid #dfe5ee;
border-bottom: 1px solid #dfe5ee;
}
.vote-table tr > :last-child {
border-right: 0;
}
.vote-table tbody tr:last-child td {
border-bottom: 0;
}
</style>
<!--#