HarmonyOS ArkTS 实战:实现一个校园学术会议与研讨会报名应用
·
HarmonyOS ArkTS 实战:从零实现校园学术会议与研讨会报名系统
目录
- 一、项目背景与效果预览
- 二、技术栈与开发环境
- 三、需求分析与功能架构
- 四、数据结构与服务层设计
- 五、核心功能实现(完整代码)
- 六、UI 界面设计与实现(完整组件)
- 七、完整主页面代码(Index.ets)及子页面
- 八、运行与调试
- 九、项目总结与扩展思路
一、项目背景与效果预览
1.1 痛点场景
校园内学术讲座、研讨会、国际会议频繁,但报名流程混乱、日程通知不及时、论文提交渠道不统一、签到靠手写……本应用打造一个一站式学术会议平台,涵盖会议浏览、在线报名、日程查看、论文提交、签到、资料下载、嘉宾介绍、参会统计,提升学术活动组织效率。
1.2 运行效果(模拟器预览)
- 主界面:顶部为海报轮播(显示热门会议图片);中部为会议列表(卡片展示会议名称、时间、地点、报名状态、剩余名额);底部Tabs切换“首页”、“我的会议”、“论文管理”、“统计”。
- 会议详情:点击会议卡片进入详情页,显示完整信息、日程(时间线)、嘉宾列表、报名按钮(已满或已报则禁用)。
- 论文提交:在论文管理Tab中可提交新论文(选择会议、填写标题、上传附件),查看审稿状态。
- 签到:在“我的会议”中,已报名的会议显示签到入口(模拟生成签到二维码)。
- 统计:展示已报名会议数、提交论文数、参会总次数,并用图表展示各会议报名人数。
主题色采用深青色(#155E75),象征学术、严谨、专业,搭配浅灰背景。
二、技术栈与开发环境
| 技术项 | 说明 |
|---|---|
| 开发语言 | ArkTS |
| UI 框架 | ArkUI 声明式开发 |
| 状态管理 | @State / @Provide / @Consume |
| 布局方式 | List + Grid + Tabs + Swiper(轮播) |
| 数据持久化 | @ohos.data.preferences |
| 路由管理 | @ohos.router |
| 图表组件 | @ohos.arkui.advanced.Chart |
| 弹窗/提示 | @ohos.prompt / @ohos.dialog |
| 二维码生成 | 模拟(使用文本展示) |
| 开发工具 | DevEco Studio 5.0+ |
| SDK 版本 | API 24 及以上 |
三、需求分析与功能架构
3.1 核心功能清单
- 会议浏览:首页展示所有会议(可分类筛选),海报轮播推荐。
- 在线报名:点击会议卡片,进入详情页报名,实时更新剩余名额,满员后禁止报名。
- 会议日程:详情页中以时间线展示会议日程安排(每个时段的活动)。
- 论文提交:用户选择会议、填写论文标题、上传文件(模拟),提交后进入“审稿中”状态。
- 签到管理:已报名的会议在“我的会议”中生成签到二维码(模拟),点击“签到”标记已签到。
- 资料下载:会议详情页提供资料列表(如会议手册、PPT),可点击下载(模拟)。
- 嘉宾介绍:展示会议嘉宾照片(占位图)、姓名、职称、简介。
- 参会统计:以图表展示各会议报名人数,以及个人参会次数、论文数。
3.2 业务流程
用户浏览会议 → 查看详情 → 报名(名额-1) → 我的会议中出现
→ 会议前可查看日程、嘉宾 → 会议当天签到(生成二维码) → 会议后下载资料
→ 可提交论文(选择会议)→ 审稿 → 查看结果
四、数据结构与服务层设计
4.1 数据模型
// model/Conference.ets
export interface Conference {
id: number;
name: string;
theme: string;
time: string; // 会议时间区间
location: string;
organizer: string;
deadline: string; // 报名截止日期
fee: number; // 费用(0为免费)
participants: number; // 已报名人数
maxParticipants: number;
isRegistered: boolean; // 当前用户是否已报名
status: '即将开始' | '进行中' | '已结束';
bannerImage: string; // 海报图片资源名
schedule: ScheduleItem[]; // 日程
speakers: Speaker[]; // 嘉宾
materials: Material[]; // 资料
}
export interface ScheduleItem {
time: string; // 如 "09:00-10:00"
title: string;
speaker: string;
location: string; // 会场
}
export interface Speaker {
name: string;
title: string; // 职称/职务
avatar: string; // 头像资源名
bio: string;
}
export interface Material {
name: string;
url: string; // 模拟下载链接
size: string; // 文件大小
}
// model/Paper.ets
export interface Paper {
id: number;
conferenceId: number;
conferenceName: string;
title: string;
author: string;
coAuthors?: string[];
submitTime: string;
status: '审稿中' | '已录用' | '已拒绝' | '需修改';
reviewComment: string;
file: string; // 附件文件名
}
4.2 服务层(Service)
沿用 BaseService 模式,实现 ConferenceService、PaperService。
// service/ConferenceService.ets
import { BaseService } from './BaseService';
import { Conference, ScheduleItem, Speaker, Material } from '../model/Conference';
class ConferenceService extends BaseService<Conference> {
constructor() { super('ConfPrefs', 'conferences'); }
async fetch(): Promise<Conference[]> {
const data = await this.loadData();
if (data.length === 0) {
const mock = this.getMockData();
await this.saveData(mock);
return mock;
}
return data;
}
async add(item: Conference): Promise<Conference[]> { /* ... */ }
async update(id: number, newItem: Conference): Promise<Conference[]> { /* ... */ }
async delete(id: number): Promise<Conference[]> { /* ... */ }
private getMockData(): Conference[] {
const now = Date.now();
return [
{
id: 1,
name: '2026年人工智能与教育国际研讨会',
theme: 'AI赋能未来教育',
time: '2026-08-15 09:00 ~ 2026-08-17 17:00',
location: '学术报告厅',
organizer: '计算机学院',
deadline: '2026-08-01',
fee: 200,
participants: 45,
maxParticipants: 100,
isRegistered: false,
status: '即将开始',
bannerImage: 'banner_ai',
schedule: [
{ time: '08-15 09:00-10:00', title: '开幕式及主题报告', speaker: '张院士', location: '主会场' },
{ time: '08-15 10:30-12:00', title: 'AI教育应用分论坛', speaker: '李教授', location: '分会场A' },
{ time: '08-16 14:00-16:00', title: '圆桌讨论', speaker: '多位嘉宾', location: '主会场' }
],
speakers: [
{ name: '张院士', title: '中国科学院院士', avatar: 'avatar_zhang', bio: '人工智能专家,教育信息化领军人物' },
{ name: '李教授', title: '清华大学教授', avatar: 'avatar_li', bio: '教育技术学权威' }
],
materials: [
{ name: '会议手册.pdf', url: '/manual.pdf', size: '2.3MB' },
{ name: '主题报告PPT.pptx', url: '/ppt.pptx', size: '5.1MB' }
]
},
{
id: 2,
name: '大数据与智慧校园研讨会',
theme: '数据驱动校园治理',
time: '2026-09-10 08:30 ~ 2026-09-11 12:00',
location: '图书馆报告厅',
organizer: '信息中心',
deadline: '2026-09-01',
fee: 0,
participants: 80,
maxParticipants: 80,
isRegistered: true,
status: '即将开始',
bannerImage: 'banner_bigdata',
schedule: [ /* 略 */ ],
speakers: [ /* 略 */ ],
materials: [ /* 略 */ ]
}
];
}
}
export const conferenceService = new ConferenceService();
// service/PaperService.ets(略)
五、核心功能实现(完整代码)
5.1 页面状态与数据加载(主页面 Index.ets)
使用 Tabs 切换首页、我的会议、论文管理、统计。
// pages/Index.ets
import { Conference } from '../model/Conference';
import { Paper } from '../model/Paper';
import { conferenceService } from '../service/ConferenceService';
import { paperService } from '../service/PaperService';
import prompt from '@ohos.prompt';
import router from '@ohos.router';
import { Chart, ChartType } from '@ohos.arkui.advanced';
@Entry
@Component
struct Index {
@State conferences: Conference[] = [];
@State papers: Paper[] = [];
@State currentTabIndex: number = 0;
@State isLoading: boolean = true;
@State bannerIndex: number = 0;
// 论文提交弹窗
@State isPaperDialogVisible: boolean = false;
@State paperConferenceId: number = -1;
@State paperTitle: string = '';
@State paperFile: string = '';
// 签到状态
@State signedConferences: Set<number> = new Set();
aboutToAppear() {
this.loadData();
}
async loadData() {
this.isLoading = true;
try {
this.conferences = await conferenceService.fetch();
this.papers = await paperService.fetch();
} catch (e) {
prompt.showToast({ message: '数据加载失败' });
} finally {
this.isLoading = false;
}
}
// 报名
private async register(conferenceId: number) {
const conf = this.conferences.find(c => c.id === conferenceId);
if (!conf) return;
if (conf.participants >= conf.maxParticipants) {
prompt.showToast({ message: '会议已满员' });
return;
}
if (conf.isRegistered) {
prompt.showToast({ message: '您已报名' });
return;
}
const updated = { ...conf, isRegistered: true, participants: conf.participants + 1 };
try {
this.conferences = await conferenceService.update(conferenceId, updated);
prompt.showToast({ message: '报名成功!' });
} catch (e) {
prompt.showToast({ message: '报名失败' });
}
}
// 签到
private async signIn(conferenceId: number) {
if (this.signedConferences.has(conferenceId)) {
prompt.showToast({ message: '已签到' });
return;
}
// 模拟签到逻辑:可记录签到时间等
this.signedConferences.add(conferenceId);
prompt.showToast({ message: '签到成功!' });
}
// ... 其他方法
}
5.2 会议信息展示与报名(含剩余名额)
在首页展示会议列表,点击卡片进入详情页(或直接在首页报名,为了简洁我们放详情页)。这里我们在首页展示简要信息,点击进入详情页。
@Builder ConferenceCard(conf: Conference) {
Column() {
Row() {
// 海报缩略图(纯色占位)
Row().width(80).height(80).backgroundColor('#E5E7EB').borderRadius(8)
.overlay(Text('📷').fontSize(20).fontColor('#999'));
Column() {
Text(conf.name).fontSize(16).fontWeight(FontWeight.Medium).maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis });
Text(`${conf.time.slice(0,16)}`).fontSize(12).fontColor('#666').margin({ top: 2 });
Text(`${conf.location}`).fontSize(12).fontColor('#666');
Row() {
Text(`报名 ${conf.participants}/${conf.maxParticipants}`).fontSize(12).fontColor('#155E75');
Blank();
if (conf.isRegistered) {
Text('已报名').fontSize(12).fontColor('#10B981');
} else if (conf.participants >= conf.maxParticipants) {
Text('已满').fontSize(12).fontColor('#EF4444');
} else {
Text('可报名').fontSize(12).fontColor('#F59E0B');
}
}
.width('100%')
.margin({ top: 4 });
}
.layoutWeight(1)
.margin({ left: 10 })
.alignItems(HorizontalAlign.Start);
}
.width('100%')
.padding(10)
.backgroundColor('#FFF')
.borderRadius(8)
.shadow({ radius: 2, color: '#00000010' })
.onClick(() => {
router.pushUrl({ url: 'pages/Detail', params: { conferenceId: conf.id } });
});
}
.margin({ bottom: 10 });
}
详情页 Detail.ets(摘要):
// pages/Detail.ets
import router from '@ohos.router';
import { Conference } from '../model/Conference';
import { conferenceService } from '../service/ConferenceService';
import prompt from '@ohos.prompt';
@Entry
@Component
struct Detail {
@State conf: Conference | null = null;
private confId: number = -1;
aboutToAppear() {
const params = router.getParams() as { conferenceId: number };
if (params) {
this.confId = params.conferenceId;
this.loadConf();
}
}
async loadConf() {
const list = await conferenceService.fetch();
this.conf = list.find(c => c.id === this.confId) || null;
}
build() {
Column() {
if (this.conf) {
Scroll() {
Column({ space: 12 }) {
Text(this.conf.name).fontSize(20).fontWeight(FontWeight.Bold).width('100%');
Text(`主题:${this.conf.theme}`).fontSize(14).width('100%');
Text(`时间:${this.conf.time}`).fontSize(14);
Text(`地点:${this.conf.location}`).fontSize(14);
Text(`主办:${this.conf.organizer}`).fontSize(14);
Text(`报名截止:${this.conf.deadline}`).fontSize(14);
Text(`费用:${this.conf.fee === 0 ? '免费' : '¥'+this.conf.fee}`).fontSize(14);
Text(`已报名:${this.conf.participants}/${this.conf.maxParticipants}`).fontSize(14);
// 报名按钮
if (this.conf.isRegistered) {
Button('已报名').enabled(false).backgroundColor('#10B981');
} else if (this.conf.participants >= this.conf.maxParticipants) {
Button('已满员').enabled(false).backgroundColor('#EF4444');
} else {
Button('立即报名').backgroundColor('#155E75').onClick(() => {
// 调用父页面的报名?可以通过事件或直接调用服务,但为解耦,可在本页调用服务
// 简化:通过路由传参,让首页刷新?或直接在本页更新
this.doRegister();
});
}
// 日程时间线
this.ScheduleTimeline();
// 嘉宾列表
this.SpeakerList();
// 资料下载
this.MaterialList();
}
.padding(16)
.alignItems(HorizontalAlign.Start)
}
.layoutWeight(1)
}
}
.width('100%')
.height('100%')
.backgroundColor('#F9FAFB')
}
private async doRegister() {
if (!this.conf) return;
if (this.conf.isRegistered || this.conf.participants >= this.conf.maxParticipants) return;
const updated = { ...this.conf, isRegistered: true, participants: this.conf.participants + 1 };
try {
const list = await conferenceService.update(this.conf.id, updated);
// 从列表中取最新
this.conf = list.find(c => c.id === this.conf.id) || null;
prompt.showToast({ message: '报名成功' });
} catch (e) { prompt.showToast({ message: '报名失败' }); }
}
@Builder ScheduleTimeline() {
Column() {
Text('📅 会议日程').fontSize(16).fontWeight(FontWeight.Medium).margin({ top: 12 });
ForEach(this.conf?.schedule || [], (item: any) => {
Row() {
Column() {
Circle({ width: 10, height: 10 }).fill('#155E75');
if (item !== this.conf?.schedule[this.conf.schedule.length-1]) {
Rect({ width: 2, height: 40 }).fill('#D1D5DB');
}
}.width(20).alignItems(HorizontalAlign.Center);
Column() {
Text(item.time).fontSize(13).fontWeight(FontWeight.Medium);
Text(item.title).fontSize(14);
Text(`主讲:${item.speaker} | 地点:${item.location}`).fontSize(12).fontColor('#666');
}
.alignItems(HorizontalAlign.Start)
.margin({ left: 8 })
.layoutWeight(1);
}
.width('100%')
.padding({ top: 4, bottom: 4 });
});
}
.width('100%')
}
@Builder SpeakerList() {
Column() {
Text('👤 演讲嘉宾').fontSize(16).fontWeight(FontWeight.Medium).margin({ top: 12 });
ForEach(this.conf?.speakers || [], (speaker: any) => {
Row() {
Circle({ width: 40, height: 40 }).fill('#D1D5DB')
.overlay(Text(speaker.avatar).fontSize(20).fontColor('#999'));
Column() {
Text(speaker.name).fontSize(15).fontWeight(FontWeight.Medium);
Text(speaker.title).fontSize(12).fontColor('#666');
Text(speaker.bio).fontSize(12).fontColor('#999').maxLines(2).textOverflow({ overflow: TextOverflow.Ellipsis });
}
.margin({ left: 10 })
.layoutWeight(1)
.alignItems(HorizontalAlign.Start);
}
.width('100%')
.padding({ top: 6, bottom: 6 });
});
}
.width('100%')
}
@Builder MaterialList() {
Column() {
Text('📁 会议资料').fontSize(16).fontWeight(FontWeight.Medium).margin({ top: 12 });
ForEach(this.conf?.materials || [], (material: any) => {
Row() {
Text(`📄 ${material.name}`).layoutWeight(1);
Text(material.size).fontSize(12).fontColor('#999');
Button('下载')
.onClick(() => prompt.showToast({ message: `开始下载 ${material.name}` }))
.height(28).fontSize(12).backgroundColor('#155E75');
}
.width('100%')
.padding({ top: 6, bottom: 6 })
.border({ width: { bottom: 1 }, color: '#F0F0F0' });
});
}
.width('100%')
}
}
5.3 会议日程时间线(可展开)
已在详情页中实现,见上。
5.4 论文提交(含文件上传模拟)
在“论文管理”Tab中,可提交新论文。
// 在 Index.ets 的论文管理 Tab 中
TabContent() {
Column() {
Text('📝 我的论文').fontSize(18).fontWeight(FontWeight.Bold).margin(12).alignSelf(ItemAlign.Start);
Button('提交新论文')
.backgroundColor('#155E75')
.margin(12)
.onClick(() => {
// 弹出选择会议对话框
const confNames = this.conferences.map(c => c.name);
prompt.showDialog({
title: '选择会议',
items: confNames,
buttons: [{ text: '取消' }, { text: '确定' }]
}).then(result => {
if (result.index === 1 && result.value !== undefined) {
const selectedName = confNames[result.value];
const conf = this.conferences.find(c => c.name === selectedName);
if (conf) {
this.paperConferenceId = conf.id;
this.paperTitle = '';
this.paperFile = '';
this.isPaperDialogVisible = true;
}
}
});
});
List() {
ForEach(this.papers, (paper: Paper) => {
ListItem() {
Row() {
Column() {
Text(paper.title).fontSize(15).fontWeight(FontWeight.Medium);
Text(`会议:${paper.conferenceName} | 提交:${paper.submitTime.slice(0,10)}`).fontSize(12).fontColor('#666');
Text(`状态:${paper.status}`).fontSize(12).fontColor(
paper.status === '已录用' ? '#10B981' :
paper.status === '已拒绝' ? '#EF4444' : '#F59E0B'
);
}
.alignItems(HorizontalAlign.Start)
.layoutWeight(1);
Text(paper.file).fontSize(11).fontColor('#999');
}
.width('100%')
.padding(10)
.border({ width: { bottom: 1 }, color: '#F0F0F0' });
}
});
}
.width('100%')
.layoutWeight(1)
}
}
.tabBar('📝 论文')
论文提交弹窗:
@Builder PaperDialogContent() {
Column() {
Text('提交论文').fontSize(18).fontWeight(FontWeight.Bold).margin(12);
Text(`会议:${this.conferences.find(c => c.id === this.paperConferenceId)?.name || ''}`).margin(4);
TextInput({ placeholder: '论文标题', text: this.paperTitle }).onChange(v => this.paperTitle = v).margin(6);
Row() {
Text('附件:').width(60);
Button('选择文件(模拟)').onClick(() => {
prompt.showDialog({
title: '选择文件',
message: '支持 PDF, Word',
buttons: [{ text: '选择PDF' }, { text: '选择Word' }, { text: '取消' }]
}).then(result => {
if (result.index !== 2) {
this.paperFile = result.index === 0 ? 'paper.pdf' : 'paper.docx';
prompt.showToast({ message: `已选择 ${this.paperFile}` });
}
});
}).height(30).fontSize(12);
}.margin(6);
if (this.paperFile) Text(`已选:${this.paperFile}`).fontSize(12).fontColor('#155E75');
Row() {
Button('取消').onClick(() => this.isPaperDialogVisible = false).backgroundColor('#999');
Button('提交').onClick(() => this.submitPaper()).backgroundColor('#155E75').margin({ left: 20 });
}.margin(16);
}
.padding(20)
.width('90%')
.backgroundColor('#FFF')
.borderRadius(16);
}
private async submitPaper() {
if (!this.paperTitle.trim()) { prompt.showToast({ message: '请输入标题' }); return; }
if (!this.paperFile) { prompt.showToast({ message: '请选择附件' }); return; }
const conf = this.conferences.find(c => c.id === this.paperConferenceId);
if (!conf) return;
const paper: Paper = {
id: Date.now(),
conferenceId: conf.id,
conferenceName: conf.name,
title: this.paperTitle.trim(),
author: '我',
submitTime: new Date().toISOString(),
status: '审稿中',
reviewComment: '',
file: this.paperFile
};
try {
this.papers = await paperService.add(paper);
prompt.showToast({ message: '论文提交成功' });
this.isPaperDialogVisible = false;
} catch (e) {
prompt.showToast({ message: '提交失败' });
}
}
5.5 签到管理(二维码模拟)
在“我的会议”Tab中,展示已报名会议,提供签到按钮,点击后展示二维码(模拟)。
TabContent() {
Column() {
Text('📌 我的会议').fontSize(18).fontWeight(FontWeight.Bold).margin(12).alignSelf(ItemAlign.Start);
List() {
ForEach(this.conferences.filter(c => c.isRegistered), (conf: Conference) => {
ListItem() {
Column() {
Row() {
Text(conf.name).fontSize(16).fontWeight(FontWeight.Medium).layoutWeight(1);
Text(conf.status).fontSize(12).fontColor(
conf.status === '即将开始' ? '#F59E0B' :
conf.status === '进行中' ? '#3B82F6' : '#999'
);
}.width('100%');
Text(`${conf.time.slice(0,16)} ${conf.location}`).fontSize(13).fontColor('#666').width('100%').margin({ top: 4 });
Row() {
if (this.signedConferences.has(conf.id)) {
Text('✅ 已签到').fontColor('#10B981');
} else {
Button('签到').onClick(() => this.signIn(conf.id)).backgroundColor('#155E75').height(28).fontSize(12);
Button('查看签到码').onClick(() => {
// 模拟二维码,显示文本
prompt.showDialog({
title: '签到二维码(模拟)',
message: `签到码:CONF-${conf.id}-${conf.name.slice(0,4)}`,
buttons: [{ text: '确定' }]
});
}).backgroundColor('#F59E0B').height(28).fontSize(12).margin({ left: 8 });
}
}
.width('100%')
.justifyContent(FlexAlign.End)
.margin({ top: 6 });
}
.width('100%')
.padding(12)
.backgroundColor('#FFF')
.borderRadius(8)
.margin({ bottom: 8 });
}
});
}
.width('100%')
.layoutWeight(1)
}
}
.tabBar('📋 我的会议')
5.6 资料下载与嘉宾介绍
已在详情页中实现。
5.7 数据统计图表(参会/论文分布)
在“统计”Tab中展示。
TabContent() {
Column() {
Text('📊 参会统计').fontSize(18).fontWeight(FontWeight.Bold).margin(12).alignSelf(ItemAlign.Start);
// 个人统计
Row() {
Column() { Text('已报名').fontSize(12).fontColor('#666'); Text(`${this.conferences.filter(c => c.isRegistered).length}`).fontSize(20).fontWeight(FontWeight.Bold); }
.layoutWeight(1).alignItems(HorizontalAlign.Center);
Column() { Text('提交论文').fontSize(12).fontColor('#666'); Text(`${this.papers.length}`).fontSize(20).fontWeight(FontWeight.Bold); }
.layoutWeight(1).alignItems(HorizontalAlign.Center);
Column() { Text('已签到').fontSize(12).fontColor('#666'); Text(`${this.signedConferences.size}`).fontSize(20).fontWeight(FontWeight.Bold); }
.layoutWeight(1).alignItems(HorizontalAlign.Center);
}
.width('100%')
.padding(12)
.backgroundColor('#F3F4F6')
.borderRadius(8)
.margin({ bottom: 16 });
// 各会议报名人数柱状图
const confNames = this.conferences.map(c => c.name.slice(0,6));
const participants = this.conferences.map(c => c.participants);
if (confNames.length > 0) {
Chart({
type: ChartType.Bar,
datasets: [{ data: participants, color: '#155E75' }],
options: {
xAxis: { labels: confNames, color: '#999' },
yAxis: { min: 0, step: 10, color: '#999' }
}
}).width('100%').height(150);
}
}
.padding(10)
}
.tabBar('📊 统计')
5.8 数据持久化(Preferences)
已在服务层实现,每次修改自动保存。
六、UI 界面设计与实现(完整组件)
6.1 顶部海报轮播(Banner)
在首页顶部添加 Swiper 轮播。
@Builder BannerSwiper() {
Swiper() {
ForEach(this.conferences.filter(c => c.bannerImage), (conf: Conference) => {
Row()
.width('100%')
.height(150)
.backgroundColor('#155E75')
.borderRadius(8)
.overlay(Text(conf.name).fontSize(16).fontColor('#FFF').shadow({ radius: 4 }))
})
}
.autoPlay(true)
.interval(3000)
.indicator(true)
.width('100%')
.height(150)
.margin({ bottom: 12 })
}
6.2 会议列表卡片
见 ConferenceCard。
6.3 日程时间线
见详情页中的 ScheduleTimeline。
6.4 论文提交入口与状态
见“论文管理”Tab。
6.5 我的会议与签到入口
见“我的会议”Tab。
七、完整主页面代码(Index.ets)及子页面
Index.ets 完整结构如下(组合所有片段):
// Index.ets
// ... 导入
@Entry
@Component
struct Index {
// 所有状态
// 所有方法
// Builders
build() {
Column() {
Tabs({ barPosition: BarPosition.End }) {
TabContent() { // 首页
if (this.isLoading) LoadingProgress().color('#155E75');
else {
Scroll() {
Column() {
this.BannerSwiper();
ForEach(this.conferences, (conf: Conference) => {
this.ConferenceCard(conf);
});
}
.padding(10)
}
.layoutWeight(1)
}
}.tabBar('🏠 首页')
TabContent() { /* 我的会议 */ }.tabBar('📋 我的会议')
TabContent() { /* 论文管理 */ }.tabBar('📝 论文')
TabContent() { /* 统计 */ }.tabBar('📊 统计')
}
.width('100%')
.layoutWeight(1)
}
.width('100%')
.height('100%')
.backgroundColor('#F9FAFB')
.dialog($$this.isPaperDialogVisible, this.PaperDialogContent())
}
}
子页面 Detail.ets 和 Certificate.ets(可省略)已在前文给出。
八、运行与调试
8.1 环境
- DevEco Studio 5.0+,API 24。
- 无需额外权限。
8.2 运行
- 导入完整项目,包含服务层和模型。
- 运行模拟器,测试会议浏览、报名、日程、论文提交、签到、统计等功能。
8.3 调试
- 使用 HiLog 打印操作日志。
- 测试满员报名、重复报名等边界情况。
九、项目总结与扩展思路
9.1 项目总结
- 功能完整:覆盖会议管理全生命周期(浏览→报名→参会→签到→论文提交)。
- 交互丰富:轮播、时间线、弹窗、图表、二维码模拟。
- 工程化:分层服务、数据持久化、路由分离。
- 可扩展性:易于增加线上直播、互动问答等功能。
9.2 扩展方向
- 线上直播:接入直播组件,支持远程参会。
- 会议笔记:参会时记录笔记,云端同步。
- 提问互动:会中提问、弹幕。
- 论文录用通知:状态变化时推送消息。
- 学分认定:参会可获学分,自动关联教务系统。
- 多语言支持:国际化。
运行效果

更多推荐

所有评论(0)