Merge remote-tracking branch 'origin/master_develop' into master_develop

This commit is contained in:
En 2026-04-15 15:23:05 +08:00
commit ee9a519d57
8 changed files with 183 additions and 132 deletions

View File

@ -10,10 +10,12 @@ import com.lesingle.common.result.PageResult;
import com.lesingle.modules.biz.contest.entity.BizContest; import com.lesingle.modules.biz.contest.entity.BizContest;
import com.lesingle.modules.biz.contest.entity.BizContestAttachment; import com.lesingle.modules.biz.contest.entity.BizContestAttachment;
import com.lesingle.modules.biz.contest.entity.BizContestNotice; import com.lesingle.modules.biz.contest.entity.BizContestNotice;
import com.lesingle.modules.biz.contest.entity.BizContestNoticeAttachment;
import com.lesingle.modules.biz.contest.entity.BizContestRegistration; import com.lesingle.modules.biz.contest.entity.BizContestRegistration;
import com.lesingle.modules.biz.contest.entity.BizContestWork; import com.lesingle.modules.biz.contest.entity.BizContestWork;
import com.lesingle.modules.biz.contest.mapper.ContestAttachmentMapper; import com.lesingle.modules.biz.contest.mapper.ContestAttachmentMapper;
import com.lesingle.modules.biz.contest.mapper.ContestMapper; import com.lesingle.modules.biz.contest.mapper.ContestMapper;
import com.lesingle.modules.biz.contest.mapper.ContestNoticeAttachmentMapper;
import com.lesingle.modules.biz.contest.mapper.ContestNoticeMapper; import com.lesingle.modules.biz.contest.mapper.ContestNoticeMapper;
import com.lesingle.modules.biz.contest.mapper.ContestRegistrationMapper; import com.lesingle.modules.biz.contest.mapper.ContestRegistrationMapper;
import com.lesingle.modules.biz.contest.mapper.ContestWorkMapper; import com.lesingle.modules.biz.contest.mapper.ContestWorkMapper;
@ -50,6 +52,7 @@ public class PublicActivityService {
private final UgcWorkMapper ugcWorkMapper; private final UgcWorkMapper ugcWorkMapper;
private final UgcWorkPageMapper ugcWorkPageMapper; private final UgcWorkPageMapper ugcWorkPageMapper;
private final ContestNoticeMapper contestNoticeMapper; private final ContestNoticeMapper contestNoticeMapper;
private final ContestNoticeAttachmentMapper contestNoticeAttachmentMapper;
private final ContestAttachmentMapper contestAttachmentMapper; private final ContestAttachmentMapper contestAttachmentMapper;
private final SysUserMapper sysUserMapper; private final SysUserMapper sysUserMapper;
@ -163,6 +166,31 @@ public class PublicActivityService {
m.put("createTime", n.getCreateTime()); m.put("createTime", n.getCreateTime());
list.add(m); list.add(m);
} }
if (!rows.isEmpty()) {
List<Long> noticeIds = rows.stream().map(BizContestNotice::getId).filter(Objects::nonNull).toList();
LambdaQueryWrapper<BizContestNoticeAttachment> attw = new LambdaQueryWrapper<>();
attw.in(BizContestNoticeAttachment::getNoticeId, noticeIds);
attw.orderByAsc(BizContestNoticeAttachment::getCreateTime);
List<BizContestNoticeAttachment> attRows = contestNoticeAttachmentMapper.selectList(attw);
Map<Long, List<BizContestNoticeAttachment>> byNotice = attRows.stream()
.collect(Collectors.groupingBy(BizContestNoticeAttachment::getNoticeId));
for (Map<String, Object> m : list) {
Long nid = (Long) m.get("id");
List<BizContestNoticeAttachment> nas = byNotice.getOrDefault(nid, Collections.emptyList());
List<Map<String, Object>> attList = new ArrayList<>();
for (BizContestNoticeAttachment a : nas) {
Map<String, Object> am = new LinkedHashMap<>();
am.put("id", a.getId());
am.put("fileName", a.getFileName());
am.put("fileUrl", a.getFileUrl());
am.put("fileType", a.getFileType());
am.put("format", a.getFormat());
am.put("size", a.getSize());
attList.add(am);
}
m.put("attachments", attList);
}
}
return list; return list;
} }

View File

@ -289,6 +289,15 @@ export interface PublicActivity {
workRequirement: string; workRequirement: string;
} }
export interface PublicActivityAttachment {
id: number;
fileName: string;
fileUrl: string;
fileType?: string;
format?: string;
size?: string;
}
/** 公众端活动详情(含公告、附件等扩展字段) */ /** 公众端活动详情(含公告、附件等扩展字段) */
export interface PublicActivityNotice { export interface PublicActivityNotice {
id: number; id: number;
@ -297,15 +306,8 @@ export interface PublicActivityNotice {
noticeType?: string; noticeType?: string;
publishTime?: string; publishTime?: string;
createTime?: string; createTime?: string;
} /** 公告附件(公众活动详情接口填充,与活动附件字段一致) */
attachments?: PublicActivityAttachment[];
export interface PublicActivityAttachment {
id: number;
fileName: string;
fileUrl: string;
fileType?: string;
format?: string;
size?: string;
} }
export interface PublicActivityDetail extends PublicActivity { export interface PublicActivityDetail extends PublicActivity {

View File

@ -4,15 +4,12 @@
<!-- 顶部海报区域 --> <!-- 顶部海报区域 -->
<div class="hero-section"> <div class="hero-section">
<!-- 背景图 --> <!-- 背景图 -->
<div <div class="hero-bg" :style="{
class="hero-bg" backgroundImage:
:style="{ contest?.posterUrl || contest?.coverUrl
backgroundImage: ? `url(${contest.posterUrl || contest.coverUrl})`
contest?.posterUrl || contest?.coverUrl : undefined,
? `url(${contest.posterUrl || contest.coverUrl})` }">
: undefined,
}"
>
<div class="hero-overlay"></div> <div class="hero-overlay"></div>
</div> </div>
@ -46,43 +43,29 @@
<div class="hero-meta"> <div class="hero-meta">
<div class="meta-item"> <div class="meta-item">
<CalendarOutlined /> <CalendarOutlined />
<span <span>活动时间{{ formatDate(contest?.startTime) }} ~
>活动时间{{ formatDate(contest?.startTime) }} ~ {{ formatDate(contest?.endTime) }}</span>
{{ formatDate(contest?.endTime) }}</span
>
</div> </div>
<div class="meta-item"> <div class="meta-item">
<ClockCircleOutlined /> <ClockCircleOutlined />
<span <span>报名时间{{ formatDate(contest?.registerStartTime) }} ~
>报名时间{{ formatDate(contest?.registerStartTime) }} ~ {{ formatDate(contest?.registerEndTime) }}</span>
{{ formatDate(contest?.registerEndTime) }}</span
>
</div> </div>
</div> </div>
<!-- 报名按钮 --> <!-- 报名按钮 -->
<div class="hero-actions"> <div class="hero-actions">
<button <button v-if="isTeacher && isRegistering && !hasRegistered" class="action-btn primary"
v-if="isTeacher && isRegistering && !hasRegistered" @click="handleRegister">
class="action-btn primary"
@click="handleRegister"
>
<FormOutlined /> <FormOutlined />
立即报名 立即报名
</button> </button>
<button <button v-else-if="isTeacher && hasRegistered && canViewRegistration" class="action-btn secondary"
v-else-if="isTeacher && hasRegistered && canViewRegistration" @click="handleViewRegistration">
class="action-btn secondary"
@click="handleViewRegistration"
>
<EyeOutlined /> <EyeOutlined />
查看报名 查看报名
</button> </button>
<button <button v-else-if="isTeacher" class="action-btn disabled" disabled>
v-else-if="isTeacher"
class="action-btn disabled"
disabled
>
<FormOutlined /> <FormOutlined />
{{ isRegistering ? "立即报名" : "报名已截止" }} {{ isRegistering ? "立即报名" : "报名已截止" }}
</button> </button>
@ -98,30 +81,18 @@
<div class="tab-section"> <div class="tab-section">
<div class="tab-container"> <div class="tab-container">
<div class="custom-tabs"> <div class="custom-tabs">
<div <div class="tab-item" :class="{ active: activeTab === 'info' }" @click="handleTabChange('info')">
class="tab-item"
:class="{ active: activeTab === 'info' }"
@click="handleTabChange('info')"
>
<FileTextOutlined /> <FileTextOutlined />
<span>活动信息</span> <span>活动信息</span>
</div> </div>
<div <div class="tab-item" :class="{ active: activeTab === 'notices' }" @click="handleTabChange('notices')">
class="tab-item"
:class="{ active: activeTab === 'notices' }"
@click="handleTabChange('notices')"
>
<BellOutlined /> <BellOutlined />
<span>通知公告</span> <span>通知公告</span>
<span v-if="notices.length > 0" class="badge">{{ <span v-if="notices.length > 0" class="badge">{{
notices.length notices.length
}}</span> }}</span>
</div> </div>
<div <div class="tab-item" :class="{ active: activeTab === 'results' }" @click="handleTabChange('results')">
class="tab-item"
:class="{ active: activeTab === 'results' }"
@click="handleTabChange('results')"
>
<TrophyOutlined /> <TrophyOutlined />
<span>活动结果</span> <span>活动结果</span>
</div> </div>
@ -144,11 +115,7 @@
<h2>竞赛详情</h2> <h2>竞赛详情</h2>
</div> </div>
<div class="card-body"> <div class="card-body">
<div <div v-if="contest.content" class="rich-content" v-html="contest.content"></div>
v-if="contest.content"
class="rich-content"
v-html="contest.content"
></div>
<a-empty v-else description="暂无详情内容" /> <a-empty v-else description="暂无详情内容" />
</div> </div>
</div> </div>
@ -165,18 +132,11 @@
<div v-if="noticesLoading" class="loading-placeholder"> <div v-if="noticesLoading" class="loading-placeholder">
<a-spin /> <a-spin />
</div> </div>
<div <div v-else-if="notices.length === 0" class="empty-placeholder">
v-else-if="notices.length === 0"
class="empty-placeholder"
>
<a-empty description="暂无公告" /> <a-empty description="暂无公告" />
</div> </div>
<div v-else class="notice-list"> <div v-else class="notice-list">
<div <div v-for="item in notices" :key="item.id" class="notice-item">
v-for="item in notices"
:key="item.id"
class="notice-item"
>
<div class="notice-header"> <div class="notice-header">
<span class="notice-title">{{ item.title }}</span> <span class="notice-title">{{ item.title }}</span>
<span class="notice-type" :class="item.noticeType"> <span class="notice-type" :class="item.noticeType">
@ -184,6 +144,15 @@
</span> </span>
</div> </div>
<div class="notice-content">{{ item.content }}</div> <div class="notice-content">{{ item.content }}</div>
<div v-if="item.attachments?.length" class="notice-attachments-block">
<div class="notice-attachments-title">公告附件</div>
<div v-for="na in item.attachments" :key="na.id" class="notice-att-link">
<a :href="na.fileUrl" target="_blank" rel="noopener noreferrer">
<PaperClipOutlined />
{{ na.fileName }}
</a>
</div>
</div>
<div class="notice-time"> <div class="notice-time">
<ClockCircleOutlined /> <ClockCircleOutlined />
{{ formatDateTime(item.publishTime) }} {{ formatDateTime(item.publishTime) }}
@ -204,19 +173,11 @@
<div class="card-body"> <div class="card-body">
<div v-if="contest.resultState === 'published'"> <div v-if="contest.resultState === 'published'">
<a-spin :spinning="resultsLoading"> <a-spin :spinning="resultsLoading">
<a-table <a-table :columns="resultColumns" :data-source="results" :pagination="resultsPagination"
:columns="resultColumns" row-key="id" @change="handleResultsTableChange">
:data-source="results"
:pagination="resultsPagination"
row-key="id"
@change="handleResultsTableChange"
>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'rank'"> <template v-if="column.key === 'rank'">
<div <div class="rank-badge" :class="getRankClass(record.rank)">
class="rank-badge"
:class="getRankClass(record.rank)"
>
{{ record.rank || "-" }} {{ record.rank || "-" }}
</div> </div>
</template> </template>
@ -228,11 +189,7 @@
}} }}
</template> </template>
<template v-else-if="column.key === 'award'"> <template v-else-if="column.key === 'award'">
<span <span v-if="record.awardName" class="award-tag" :class="getAwardClass(record.awardName)">
v-if="record.awardName"
class="award-tag"
:class="getAwardClass(record.awardName)"
>
{{ record.awardName }} {{ record.awardName }}
</span> </span>
<span v-else>-</span> <span v-else>-</span>
@ -265,20 +222,14 @@
{{ getVisibilityText(contest?.visibility) }} {{ getVisibilityText(contest?.visibility) }}
</div> </div>
</div> </div>
<div <div v-if="contest?.visibility === 'designated' && contest?.contestTenantInfos?.length"
v-if="contest?.visibility === 'designated' && contest?.contestTenantInfos?.length" class="sidebar-item">
class="sidebar-item"
>
<div class="item-label"> <div class="item-label">
<TeamOutlined /> <TeamOutlined />
开放机构 开放机构
</div> </div>
<div class="item-value"> <div class="item-value">
<div <div v-for="tenant in contest.contestTenantInfos" :key="tenant.id" class="org-name">
v-for="tenant in contest.contestTenantInfos"
:key="tenant.id"
class="org-name"
>
{{ tenant.name }}{{ tenant.code }} {{ tenant.name }}{{ tenant.code }}
</div> </div>
</div> </div>
@ -301,6 +252,20 @@
{{ formatDateTime(contest?.createTime) }} {{ formatDateTime(contest?.createTime) }}
</div> </div>
</div> </div>
<div v-if="contest.attachments?.length" class="sidebar-item">
<div class="item-label">
<PaperClipOutlined />
活动附件
</div>
<div class="item-value">
<div v-for="att in contest.attachments" :key="att.id" class="contest-attachment-link">
<a :href="att.fileUrl" target="_blank" rel="noopener noreferrer">
<PaperClipOutlined />
{{ att.fileName }}
</a>
</div>
</div>
</div>
</div> </div>
</div> </div>
@ -318,11 +283,7 @@
<div class="item-value"> <div class="item-value">
<template v-if="contest.organizers"> <template v-if="contest.organizers">
<template v-if="Array.isArray(contest.organizers)"> <template v-if="Array.isArray(contest.organizers)">
<div <div v-for="org in contest.organizers" :key="org" class="org-name">
v-for="org in contest.organizers"
:key="org"
class="org-name"
>
{{ org }} {{ org }}
</div> </div>
</template> </template>
@ -342,11 +303,7 @@
<div class="item-value"> <div class="item-value">
<template v-if="contest.coOrganizers"> <template v-if="contest.coOrganizers">
<template v-if="Array.isArray(contest.coOrganizers)"> <template v-if="Array.isArray(contest.coOrganizers)">
<div <div v-for="org in contest.coOrganizers" :key="org" class="org-name">
v-for="org in contest.coOrganizers"
:key="org"
class="org-name"
>
{{ org }} {{ org }}
</div> </div>
</template> </template>
@ -366,11 +323,7 @@
<div class="item-value"> <div class="item-value">
<template v-if="contest.sponsors"> <template v-if="contest.sponsors">
<template v-if="Array.isArray(contest.sponsors)"> <template v-if="Array.isArray(contest.sponsors)">
<div <div v-for="sp in contest.sponsors" :key="sp" class="org-name">
v-for="sp in contest.sponsors"
:key="sp"
class="org-name"
>
{{ sp }} {{ sp }}
</div> </div>
</template> </template>
@ -381,14 +334,12 @@
<span v-else class="empty-text">暂无</span> <span v-else class="empty-text">暂无</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- 联系方式 --> <!-- 联系方式 -->
<div <div v-if="contest.contactName || contest.contactPhone" class="sidebar-card">
v-if="contest.contactName || contest.contactPhone"
class="sidebar-card"
>
<div class="sidebar-header"> <div class="sidebar-header">
<PhoneOutlined /> <PhoneOutlined />
<span>联系方式</span> <span>联系方式</span>
@ -415,11 +366,7 @@
</div> </div>
</div> </div>
<a-empty <a-empty v-else-if="!loading" description="活动不存在" style="padding: 100px 0" />
v-else-if="!loading"
description="活动不存在"
style="padding: 100px 0"
/>
</a-spin> </a-spin>
</div> </div>
</template> </template>
@ -445,6 +392,7 @@ import {
UserOutlined, UserOutlined,
GlobalOutlined, GlobalOutlined,
InfoCircleOutlined, InfoCircleOutlined,
PaperClipOutlined,
} from "@ant-design/icons-vue" } from "@ant-design/icons-vue"
import dayjs from "dayjs" import dayjs from "dayjs"
import { useAuthStore } from "@/stores/auth" import { useAuthStore } from "@/stores/auth"
@ -731,11 +679,9 @@ $primary-dark: #0958d9;
.hero-overlay { .hero-overlay {
position: absolute; position: absolute;
inset: 0; inset: 0;
background: linear-gradient( background: linear-gradient(180deg,
180deg, rgba(0, 0, 0, 0.3) 0%,
rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.6) 100%);
rgba(0, 0, 0, 0.6) 100%
);
} }
.hero-nav { .hero-nav {
@ -800,12 +746,15 @@ $primary-dark: #0958d9;
.tag-registering { .tag-registering {
background: linear-gradient(135deg, #52c41a, #73d13d); background: linear-gradient(135deg, #52c41a, #73d13d);
} }
.tag-submitting { .tag-submitting {
background: linear-gradient(135deg, #1890ff, #40a9ff); background: linear-gradient(135deg, #1890ff, #40a9ff);
} }
.tag-reviewing { .tag-reviewing {
background: linear-gradient(135deg, #faad14, #ffc53d); background: linear-gradient(135deg, #faad14, #ffc53d);
} }
.tag-finished { .tag-finished {
background: linear-gradient(135deg, #8c8c8c, #bfbfbf); background: linear-gradient(135deg, #8c8c8c, #bfbfbf);
} }
@ -1018,6 +967,7 @@ $primary-dark: #0958d9;
:deep(p) { :deep(p) {
margin-bottom: 16px; margin-bottom: 16px;
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
@ -1033,6 +983,7 @@ $primary-dark: #0958d9;
font-weight: 600; font-weight: 600;
margin-top: 24px; margin-top: 24px;
margin-bottom: 12px; margin-bottom: 12px;
&:first-child { &:first-child {
margin-top: 0; margin-top: 0;
} }
@ -1083,6 +1034,7 @@ $primary-dark: #0958d9;
:deep(a) { :deep(a) {
color: $primary; color: $primary;
text-decoration: none; text-decoration: none;
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
} }
@ -1123,6 +1075,7 @@ $primary-dark: #0958d9;
background: #fff2f0; background: #fff2f0;
color: #ff4d4f; color: #ff4d4f;
} }
&.system { &.system {
background: #e6f7ff; background: #e6f7ff;
color: #1890ff; color: #1890ff;
@ -1137,6 +1090,28 @@ $primary-dark: #0958d9;
margin-bottom: 10px; margin-bottom: 10px;
} }
.notice-attachments-block {
margin-bottom: 10px;
padding-top: 10px;
border-top: 1px solid #f0f0f0;
.notice-attachments-title {
font-size: 12px;
font-weight: 600;
color: rgba(0, 0, 0, 0.45);
margin-bottom: 6px;
}
.notice-att-link a {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: $primary;
margin-bottom: 4px;
}
}
.notice-time { .notice-time {
font-size: 12px; font-size: 12px;
color: rgba(0, 0, 0, 0.45); color: rgba(0, 0, 0, 0.45);
@ -1164,10 +1139,12 @@ $primary-dark: #0958d9;
background: linear-gradient(135deg, #ffd700, #ffb800); background: linear-gradient(135deg, #ffd700, #ffb800);
color: #fff; color: #fff;
} }
&.rank-2 { &.rank-2 {
background: linear-gradient(135deg, #c0c0c0, #a0a0a0); background: linear-gradient(135deg, #c0c0c0, #a0a0a0);
color: #fff; color: #fff;
} }
&.rank-3 { &.rank-3 {
background: linear-gradient(135deg, #cd7f32, #b8860b); background: linear-gradient(135deg, #cd7f32, #b8860b);
color: #fff; color: #fff;
@ -1185,10 +1162,12 @@ $primary-dark: #0958d9;
background: #fffbe6; background: #fffbe6;
color: #d48806; color: #d48806;
} }
&.award-silver { &.award-silver {
background: #f5f5f5; background: #f5f5f5;
color: #595959; color: #595959;
} }
&.award-bronze { &.award-bronze {
background: #fff7e6; background: #fff7e6;
color: #d46b08; color: #d46b08;
@ -1212,11 +1191,9 @@ $primary-dark: #0958d9;
align-items: center; align-items: center;
gap: 10px; gap: 10px;
padding: 16px 20px; padding: 16px 20px;
background: linear-gradient( background: linear-gradient(135deg,
135deg, rgba($primary, 0.05),
rgba($primary, 0.05), rgba($primary-dark, 0.08));
rgba($primary-dark, 0.08)
);
border-bottom: 1px solid #f0f0f0; border-bottom: 1px solid #f0f0f0;
font-size: 15px; font-size: 15px;
font-weight: 600; font-weight: 600;
@ -1269,6 +1246,15 @@ $primary-dark: #0958d9;
.empty-text { .empty-text {
color: rgba(0, 0, 0, 0.25); color: rgba(0, 0, 0, 0.25);
} }
.contest-attachment-link a {
display: inline-flex;
align-items: center;
gap: 6px;
color: $primary;
font-size: 13px;
padding: 4px 0;
}
} }
} }
} }
@ -1299,10 +1285,12 @@ $primary-dark: #0958d9;
.hero-title { .hero-title {
font-size: 24px; font-size: 24px;
} }
.hero-meta { .hero-meta {
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
} }
.hero-actions { .hero-actions {
flex-wrap: wrap; flex-wrap: wrap;
} }

View File

@ -147,6 +147,14 @@
<div v-for="notice in activity.notices" :key="notice.id" class="notice-item"> <div v-for="notice in activity.notices" :key="notice.id" class="notice-item">
<h4>{{ notice.title }}</h4> <h4>{{ notice.title }}</h4>
<div class="notice-content" v-html="sanitizeNoticeContent(notice.content)"></div> <div class="notice-content" v-html="sanitizeNoticeContent(notice.content)"></div>
<div v-if="notice.attachments?.length" class="notice-attachments">
<div class="notice-attachments-title">公告附件</div>
<div v-for="att in notice.attachments" :key="att.id" class="att-item">
<a :href="att.fileUrl" target="_blank" rel="noopener noreferrer">
<paper-clip-outlined /> {{ att.fileName }}
</a>
</div>
</div>
<span class="notice-time">{{ formatNoticeTime(notice) }}</span> <span class="notice-time">{{ formatNoticeTime(notice) }}</span>
</div> </div>
</div> </div>
@ -262,7 +270,7 @@
</div> </div>
<!-- 报名弹窗 --> <!-- 报名弹窗 -->
<a-modal v-model:open="showRegisterModal" title="活动报名" :footer="null" :width="420"> <a-modal v-model:open="showRegisterModal" title="活动报名" :footer="null" :width="420" centered>
<div class="register-modal"> <div class="register-modal">
<template v-if="isChildUser"> <template v-if="isChildUser">
<p class="modal-desc">将使用当前账号报名确认参加本活动吗</p> <p class="modal-desc">将使用当前账号报名确认参加本活动吗</p>
@ -1201,6 +1209,28 @@ $primary: #6366f1;
line-height: 1.6; line-height: 1.6;
} }
.notice-attachments {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #e5e7eb;
.notice-attachments-title {
font-size: 12px;
font-weight: 600;
color: #6b7280;
margin-bottom: 6px;
}
.att-item a {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: $primary;
padding: 4px 0;
}
}
.notice-time { .notice-time {
font-size: 12px; font-size: 12px;
color: #9ca3af; color: #9ca3af;

View File

@ -3,6 +3,7 @@
:open="open" :open="open"
title="从作品库选择作品" title="从作品库选择作品"
:width="600" :width="600"
centered
@cancel="$emit('update:open', false)" @cancel="$emit('update:open', false)"
@ok="handleConfirm" @ok="handleConfirm"
:ok-button-props="{ disabled: !selectedWork }" :ok-button-props="{ disabled: !selectedWork }"

View File

@ -68,6 +68,7 @@
title="创建子女账号" title="创建子女账号"
:footer="null" :footer="null"
:width="440" :width="440"
centered
> >
<a-form :model="createForm" layout="vertical" @finish="handleCreate" class="child-form"> <a-form :model="createForm" layout="vertical" @finish="handleCreate" class="child-form">
<a-form-item label="用户名" name="username" :rules="[{ required: true, message: '请输入用户名' }, { min: 4, message: '至少4个字符' }]"> <a-form-item label="用户名" name="username" :rules="[{ required: true, message: '请输入用户名' }, { min: 4, message: '至少4个字符' }]">
@ -109,6 +110,7 @@
title="编辑子女账号" title="编辑子女账号"
:footer="null" :footer="null"
:width="440" :width="440"
centered
> >
<a-form :model="editForm" layout="vertical" @finish="handleEdit" class="child-form"> <a-form :model="editForm" layout="vertical" @finish="handleEdit" class="child-form">
<a-form-item label="昵称" name="nickname"> <a-form-item label="昵称" name="nickname">

View File

@ -69,7 +69,7 @@
</div> </div>
<!-- 编辑个人信息弹窗 --> <!-- 编辑个人信息弹窗 -->
<a-modal v-model:open="showEditModal" title="编辑个人信息" :footer="null" :width="400"> <a-modal v-model:open="showEditModal" title="编辑个人信息" :footer="null" :width="400" centered>
<a-form layout="vertical" @finish="handleSaveProfile" style="margin-top: 16px;"> <a-form layout="vertical" @finish="handleSaveProfile" style="margin-top: 16px;">
<a-form-item label="昵称" :rules="[{ required: true, message: '请输入昵称' }]"> <a-form-item label="昵称" :rules="[{ required: true, message: '请输入昵称' }]">
<a-input v-model:value="editForm.nickname" placeholder="你的昵称" :maxlength="20" /> <a-input v-model:value="editForm.nickname" placeholder="你的昵称" :maxlength="20" />

View File

@ -158,7 +158,7 @@
</a-spin> </a-spin>
<!-- 二次确认弹窗 --> <!-- 二次确认弹窗 -->
<a-modal v-model:open="confirmVisible" :title="confirmTitle" :ok-text="confirmOkText" cancel-text="取消" <a-modal v-model:open="confirmVisible" :title="confirmTitle" :ok-text="confirmOkText" cancel-text="取消" centered
:confirm-loading="actionLoading" @ok="handleConfirmOk" @cancel="handleConfirmCancel"> :confirm-loading="actionLoading" @ok="handleConfirmOk" @cancel="handleConfirmCancel">
<p>{{ confirmContent }}</p> <p>{{ confirmContent }}</p>
</a-modal> </a-modal>