UI优化和bug修复: 1.调整小程序消息列表图标样式 2.优化web端比赛晋级页面布局 3.修复小程序消息列表日期显示问题
10个文件已修改
191 ■■■■ 已修改文件
backend/src/main/java/com/rongyichuang/player/dto/PromotionCompetitionResponse.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
backend/src/main/java/com/rongyichuang/player/service/PromotionService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
backend/src/main/resources/graphql/player.graphqls 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web/src/api/promotion.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web/src/views/carousel/index.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web/src/views/next-list.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
wx/pages/index/index.wxss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
wx/pages/message/message.wxml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
wx/pages/message/message.wxss 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
wx/pages/message/utils.wxs 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
backend/src/main/java/com/rongyichuang/player/dto/PromotionCompetitionResponse.java
@@ -10,6 +10,7 @@
public class PromotionCompetitionResponse {
    
    private Long id;
    private Long competitionId;
    private String competitionName;
    private String stageName;
    private Integer maxParticipants;
@@ -26,6 +27,7 @@
    
    public PromotionCompetitionResponse(Activity competition, Activity stage, Integer currentCount) {
        this.id = stage.getId();
        this.competitionId = competition.getId();
        this.competitionName = competition.getName();
        this.stageName = stage.getName();
        this.maxParticipants = stage.getPlayerMax();
@@ -49,6 +51,14 @@
        this.id = id;
    }
    
    public Long getCompetitionId() {
        return competitionId;
    }
    public void setCompetitionId(Long competitionId) {
        this.competitionId = competitionId;
    }
    public String getCompetitionName() {
        return competitionName;
    }
backend/src/main/java/com/rongyichuang/player/service/PromotionService.java
@@ -246,8 +246,8 @@
                return PromotionResult.failure("请选择要晋级的参赛者");
            }
            
            // 查询目标晋级阶段信息(用户点击的阶段就是要晋级到的阶段)
            Activity targetStage = activityRepository.findById(input.getCompetitionId()).orElse(null);
            // 查询目标晋级阶段信息
            Activity targetStage = activityRepository.findById(input.getTargetStageId()).orElse(null);
            if (targetStage == null) {
                return PromotionResult.failure("目标晋级阶段不存在");
            }
backend/src/main/resources/graphql/player.graphqls
@@ -19,6 +19,10 @@
    activityPlayerDetail(id: ID!): ActivityPlayerDetailResponse
    # 微信端获取选手报名状态
    getPlayerRegistrationState(activityId: ID!): PlayerRegistrationResponse
    # 获取比赛晋级列表
    promotionCompetitions(name: String, page: Int, size: Int): [PromotionCompetitionResponse!]!
    # 获取可晋级参赛者列表
    promotableParticipants(currentStageId: ID!): PromotableParticipantsResponse
}
extend type Mutation {
@@ -29,6 +33,8 @@
    submitActivityRegistration(input: ActivityRegistrationInput!): ActivityRegistrationResponse
    # 保存评委评分
    saveActivityPlayerRating(input: ActivityPlayerRatingInput!): Boolean
    # 执行学员晋级操作
    promoteParticipants(input: PromotionInput!): PromotionResult
}
type ActivityPlayer {
@@ -232,4 +238,55 @@
input ActivityPlayerRatingItemInput {
    itemId: ID!
    score: Float!
}
# 比赛晋级列表响应类型
type PromotionCompetitionResponse {
    id: ID!
    competitionId: ID!
    competitionName: String!
    stageName: String!
    maxParticipants: Int
    currentCount: Int!
    status: Int
    startTime: String
    endTime: String
    sortOrder: Int
    state: Int
}
# 可晋级参赛者列表响应类型
type PromotableParticipantsResponse {
    participants: [PromotableParticipantResponse!]!
    selectableCount: Int
    totalCount: Int
    previousStageName: String
    currentStageName: String
}
# 可晋级参赛者响应类型
type PromotableParticipantResponse {
    id: ID!
    playerName: String
    projectName: String
    phone: String
    averageScore: Float
    ratingCount: Int
    applyTime: String
    state: Int
    playerId: ID
}
# 晋级操作输入类型
input PromotionInput {
    competitionId: ID!
    participantIds: [ID!]!
    targetStageId: ID!
}
# 晋级操作结果类型
type PromotionResult {
    success: Boolean!
    message: String
    promotedCount: Int
}
web/src/api/promotion.js
@@ -5,6 +5,7 @@
  query GetPromotionCompetitions($name: String, $page: Int, $size: Int) {
    promotionCompetitions(name: $name, page: $page, size: $size) {
      id
      competitionId
      competitionName
      stageName
      maxParticipants
web/src/views/carousel/index.vue
@@ -60,8 +60,8 @@
        <el-table-column prop="createTime" label="创建时间" width="180" />
        <el-table-column label="操作" width="120" fixed="right">
          <template #default="{ row }">
            <el-button type="primary" size="small" @click="handleEdit(row)" :icon="Edit" circle title="编辑"></el-button>
            <el-button type="danger" size="small" @click="handleDelete(row)" :icon="Delete" circle title="删除"></el-button>
            <el-button text size="small" @click="handleEdit(row)" :icon="Edit" class="action-btn edit-btn" title="编辑"></el-button>
            <el-button text size="small" @click="handleDelete(row)" :icon="Delete" class="action-btn delete-btn" title="删除"></el-button>
          </template>
        </el-table-column>
      </el-table>
@@ -681,6 +681,36 @@
  }
}
/* 操作按钮样式 */
.action-btn {
  padding: 8px !important;
  margin: 0 6px;
  border-radius: 6px;
  transition: all 0.2s ease;
  background: transparent !important;
  border: none !important;
}
.edit-btn {
  color: #409eff !important;
}
.edit-btn:hover {
  color: #337ecc !important;
  background: rgba(64, 158, 255, 0.1) !important;
  transform: scale(1.2);
}
.delete-btn {
  color: #f56c6c !important;
}
.delete-btn:hover {
  color: #dd6161 !important;
  background: rgba(245, 108, 108, 0.1) !important;
  transform: scale(1.2);
}
.header-actions {
  display: flex;
  gap: 10px;
web/src/views/next-list.vue
@@ -27,7 +27,6 @@
          <el-icon><Search /></el-icon>
          搜索
        </el-button>
        <el-button @click="resetSearch">重置</el-button>
      </div>
    </div>
@@ -222,6 +221,7 @@
import { ElMessage, ElMessageBox } from 'element-plus'
import { Search, TrophyBase, InfoFilled } from '@element-plus/icons-vue'
import PromotionApi from '@/api/promotion'
import { getActivity } from '@/api/activity'
const router = useRouter()
@@ -393,6 +393,8 @@
  selectedParticipants.value = selection
}
// 确认晋级
const confirmPromotion = async () => {
  if (selectedParticipants.value.length === 0) {
@@ -418,10 +420,10 @@
      const participantIds = selectedParticipants.value.map(p => p.id)
      
      const result = await PromotionApi.promoteParticipants(
        selectedCompetition.value.id,
        participantIds,
        null // 目标阶段ID,这里可以根据需要设置
      )
          selectedCompetition.value.competitionId, // 主比赛ID
          participantIds,
          selectedCompetition.value.id // 当前阶段ID作为目标阶段ID
        )
      
      if (result && result.success) {
        ElMessage.success(result.message || `成功晋级 ${result.promotedCount} 名人员`)
@@ -558,7 +560,7 @@
.search-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  justify-content: flex-end;
  margin-bottom: 20px;
  padding: 16px;
  background-color: #f9fafb;
wx/pages/index/index.wxss
@@ -268,6 +268,14 @@
  width: 140rpx;
  text-align: center;
  /* align-self 已移除,由父级 .btn-row 控制对齐 */
  /* 移除button默认样式 */
  margin: 0;
  position: static;
  display: inline-block;
}
.ghost-btn::after {
  border: none;
}
.ghost-btn:active {
wx/pages/message/message.wxml
@@ -19,8 +19,8 @@
    <view wx:else class="message-list">
      <view wx:for="{{messages}}" wx:key="id" class="message-card">
        <view class="icon-wrapper">
          <!-- 按要求使用统一图标 -->
          <icon type="info" size="22" color="#FFFFFF"></icon>
          <!-- 使用更合适的消息图标 -->
          <text class="icon ic-comment"></text>
        </view>
        <view class="text-wrapper">
          <text class="title">{{item.content}}</text>
wx/pages/message/message.wxss
@@ -75,10 +75,10 @@
}
.icon-wrapper {
  width: 80rpx;
  height: 80rpx;
  width: 60rpx;
  height: 60rpx;
  border-radius: 50%;
  background-color: #007aff; /* 统一使用蓝色 */
  background-color: #e6f3ff; /* 浅蓝色背景 */
  display: flex;
  align-items: center;
  justify-content: center;
@@ -86,6 +86,11 @@
  flex-shrink: 0;
}
.icon-wrapper .icon {
  font-size: 28rpx;
  color: #007aff; /* 深蓝色图标 */
}
.text-wrapper {
  display: flex;
  flex-direction: column;
wx/pages/message/utils.wxs
@@ -1,19 +1,43 @@
var formatTime = function (dateStr) {
  if (!dateStr) return '';
  // 兼容 iOS
  var date = getDate(dateStr.split('-').join('/'));
  var year = date.getFullYear();
  var month = date.getMonth() + 1;
  var day = date.getDate();
  var hour = date.getHours();
  var minute = date.getMinutes();
  var formatNumber = function(n) {
    n = n.toString();
    return n[1] ? n : '0' + n;
  var date;
  // 处理时间戳(数字)
  if (typeof dateStr === 'number') {
    date = getDate(dateStr);
  }
  // 处理字符串格式的日期
  else if (typeof dateStr === 'string') {
    // 尝试直接解析
    date = getDate(dateStr);
  }
  else {
    return '';
  }
  // 检查日期对象是否创建成功
  try {
    var year = date.getFullYear();
    var month = date.getMonth() + 1;
    var day = date.getDate();
    var hour = date.getHours();
    var minute = date.getMinutes();
    // 如果获取到的值是NaN,说明日期无效
    if (year !== year || month !== month || day !== day) {
      return '';
    }
    return year + '-' + formatNumber(month) + '-' + formatNumber(day) + ' ' + formatNumber(hour) + ':' + formatNumber(minute);
  } catch (e) {
    return '';
  }
}
  return year + '-' + formatNumber(month) + '-' + formatNumber(day) + ' ' + formatNumber(hour) + ':' + formatNumber(minute);
var formatNumber = function(n) {
  n = n.toString();
  return n[1] ? n : '0' + n;
}
module.exports = {