第二期:企业信任风 UI + 打卡科目分类 + 英语语法学习模块
- 全站按 Corporate Trust 设计规范重做:靛蓝/紫罗兰渐变、Plus Jakarta Sans 自托管字体、带色阴影、卡片悬浮、氛围光斑 - 打卡任务增加科目分类(语文/数学/英语/运动/其他),孩子端按科目分组 - 英语语法自学模块:线性解锁课程 + 课后/周/月测验引擎,测验达标 自动联动当日英语打卡;家长概览显示语法进度 - 课程内容:A1→B1 完整大纲,9 周 54 课 + 9 周测 + 2 月测,讲解/例句/ 练习/测验均原创,仅参考两份语法书的主题编排 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b08f6649be
commit
6ed4d5a61e
@@ -15,3 +15,7 @@ next-env.d.ts
|
|||||||
|
|
||||||
# 系统文件
|
# 系统文件
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# 参考资料(含版权 PDF,不入库)
|
||||||
|
materials/
|
||||||
|
*.pdf
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE `task_instance` ADD `subject` enum('chinese','math','english','exercise','other') DEFAULT 'other' NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE `task_template` ADD `subject` enum('chinese','math','english','exercise','other') DEFAULT 'other' NOT NULL;
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
CREATE TABLE `grammar_progress` (
|
||||||
|
`id` bigint AUTO_INCREMENT NOT NULL,
|
||||||
|
`child_user_id` bigint NOT NULL,
|
||||||
|
`seq` int NOT NULL,
|
||||||
|
`score` int,
|
||||||
|
`passed` boolean NOT NULL DEFAULT false,
|
||||||
|
`completed_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
CONSTRAINT `grammar_progress_id` PRIMARY KEY(`id`),
|
||||||
|
CONSTRAINT `uq_grammar_child_seq` UNIQUE(`child_user_id`,`seq`)
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE `grammar_progress` ADD CONSTRAINT `grammar_progress_child_user_id_user_id_fk` FOREIGN KEY (`child_user_id`) REFERENCES `user`(`id`) ON DELETE cascade ON UPDATE no action;
|
||||||
@@ -0,0 +1,635 @@
|
|||||||
|
{
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "mysql",
|
||||||
|
"id": "344969b3-8a75-4900-b08f-c3407340d1c4",
|
||||||
|
"prevId": "a044f535-beea-4fe6-8db5-3ae0019977de",
|
||||||
|
"tables": {
|
||||||
|
"activation_code": {
|
||||||
|
"name": "activation_code",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"child_user_id": {
|
||||||
|
"name": "child_user_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"code_hash": {
|
||||||
|
"name": "code_hash",
|
||||||
|
"type": "varchar(64)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
"name": "created_by",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"used_at": {
|
||||||
|
"name": "used_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"activation_code_child_user_id_user_id_fk": {
|
||||||
|
"name": "activation_code_child_user_id_user_id_fk",
|
||||||
|
"tableFrom": "activation_code",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"child_user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"activation_code_created_by_user_id_fk": {
|
||||||
|
"name": "activation_code_created_by_user_id_fk",
|
||||||
|
"tableFrom": "activation_code",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"created_by"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"activation_code_id": {
|
||||||
|
"name": "activation_code_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"family": {
|
||||||
|
"name": "family",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(50)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"family_id": {
|
||||||
|
"name": "family_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"photo": {
|
||||||
|
"name": "photo",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"task_instance_id": {
|
||||||
|
"name": "task_instance_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"oss_key": {
|
||||||
|
"name": "oss_key",
|
||||||
|
"type": "varchar(300)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_photo_instance": {
|
||||||
|
"name": "idx_photo_instance",
|
||||||
|
"columns": [
|
||||||
|
"task_instance_id"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"photo_task_instance_id_task_instance_id_fk": {
|
||||||
|
"name": "photo_task_instance_id_task_instance_id_fk",
|
||||||
|
"tableFrom": "photo",
|
||||||
|
"tableTo": "task_instance",
|
||||||
|
"columnsFrom": [
|
||||||
|
"task_instance_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"photo_id": {
|
||||||
|
"name": "photo_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"session": {
|
||||||
|
"name": "session",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"token_hash": {
|
||||||
|
"name": "token_hash",
|
||||||
|
"type": "varchar(64)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_label": {
|
||||||
|
"name": "device_label",
|
||||||
|
"type": "varchar(100)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"uq_session_token": {
|
||||||
|
"name": "uq_session_token",
|
||||||
|
"columns": [
|
||||||
|
"token_hash"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
},
|
||||||
|
"idx_session_user": {
|
||||||
|
"name": "idx_session_user",
|
||||||
|
"columns": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"session_user_id_user_id_fk": {
|
||||||
|
"name": "session_user_id_user_id_fk",
|
||||||
|
"tableFrom": "session",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"session_id": {
|
||||||
|
"name": "session_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"task_instance": {
|
||||||
|
"name": "task_instance",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"child_user_id": {
|
||||||
|
"name": "child_user_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"name": "date",
|
||||||
|
"type": "date",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "varchar(100)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"name": "subject",
|
||||||
|
"type": "enum('chinese','math','english','exercise','other')",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'other'"
|
||||||
|
},
|
||||||
|
"requires_photo": {
|
||||||
|
"name": "requires_photo",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "enum('pending','done')",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'pending'"
|
||||||
|
},
|
||||||
|
"is_makeup": {
|
||||||
|
"name": "is_makeup",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"done_at": {
|
||||||
|
"name": "done_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"sort_order": {
|
||||||
|
"name": "sort_order",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"source_template_id": {
|
||||||
|
"name": "source_template_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_instance_child_date": {
|
||||||
|
"name": "idx_instance_child_date",
|
||||||
|
"columns": [
|
||||||
|
"child_user_id",
|
||||||
|
"date"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"task_instance_child_user_id_user_id_fk": {
|
||||||
|
"name": "task_instance_child_user_id_user_id_fk",
|
||||||
|
"tableFrom": "task_instance",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"child_user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"task_instance_id": {
|
||||||
|
"name": "task_instance_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"task_template": {
|
||||||
|
"name": "task_template",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"child_user_id": {
|
||||||
|
"name": "child_user_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"dow": {
|
||||||
|
"name": "dow",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "varchar(100)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"name": "subject",
|
||||||
|
"type": "enum('chinese','math','english','exercise','other')",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'other'"
|
||||||
|
},
|
||||||
|
"requires_photo": {
|
||||||
|
"name": "requires_photo",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"sort_order": {
|
||||||
|
"name": "sort_order",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_template_child_dow": {
|
||||||
|
"name": "idx_template_child_dow",
|
||||||
|
"columns": [
|
||||||
|
"child_user_id",
|
||||||
|
"dow"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"task_template_child_user_id_user_id_fk": {
|
||||||
|
"name": "task_template_child_user_id_user_id_fk",
|
||||||
|
"tableFrom": "task_template",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"child_user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"task_template_id": {
|
||||||
|
"name": "task_template_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"name": "user",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"family_id": {
|
||||||
|
"name": "family_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "enum('parent','child')",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"display_name": {
|
||||||
|
"name": "display_name",
|
||||||
|
"type": "varchar(50)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"phone": {
|
||||||
|
"name": "phone",
|
||||||
|
"type": "varchar(20)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"password_hash": {
|
||||||
|
"name": "password_hash",
|
||||||
|
"type": "varchar(100)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"sort_order": {
|
||||||
|
"name": "sort_order",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"uq_user_phone": {
|
||||||
|
"name": "uq_user_phone",
|
||||||
|
"columns": [
|
||||||
|
"phone"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"user_family_id_family_id_fk": {
|
||||||
|
"name": "user_family_id_family_id_fk",
|
||||||
|
"tableFrom": "user",
|
||||||
|
"tableTo": "family",
|
||||||
|
"columnsFrom": [
|
||||||
|
"family_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"tables": {},
|
||||||
|
"indexes": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,719 @@
|
|||||||
|
{
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "mysql",
|
||||||
|
"id": "384a621e-e735-46d7-80a5-8c925bb0ce44",
|
||||||
|
"prevId": "344969b3-8a75-4900-b08f-c3407340d1c4",
|
||||||
|
"tables": {
|
||||||
|
"activation_code": {
|
||||||
|
"name": "activation_code",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"child_user_id": {
|
||||||
|
"name": "child_user_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"code_hash": {
|
||||||
|
"name": "code_hash",
|
||||||
|
"type": "varchar(64)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
"name": "created_by",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"used_at": {
|
||||||
|
"name": "used_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {
|
||||||
|
"activation_code_child_user_id_user_id_fk": {
|
||||||
|
"name": "activation_code_child_user_id_user_id_fk",
|
||||||
|
"tableFrom": "activation_code",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"child_user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
},
|
||||||
|
"activation_code_created_by_user_id_fk": {
|
||||||
|
"name": "activation_code_created_by_user_id_fk",
|
||||||
|
"tableFrom": "activation_code",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"created_by"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"activation_code_id": {
|
||||||
|
"name": "activation_code_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"family": {
|
||||||
|
"name": "family",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "varchar(50)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"family_id": {
|
||||||
|
"name": "family_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"grammar_progress": {
|
||||||
|
"name": "grammar_progress",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"child_user_id": {
|
||||||
|
"name": "child_user_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"seq": {
|
||||||
|
"name": "seq",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"score": {
|
||||||
|
"name": "score",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"passed": {
|
||||||
|
"name": "passed",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"completed_at": {
|
||||||
|
"name": "completed_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"uq_grammar_child_seq": {
|
||||||
|
"name": "uq_grammar_child_seq",
|
||||||
|
"columns": [
|
||||||
|
"child_user_id",
|
||||||
|
"seq"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"grammar_progress_child_user_id_user_id_fk": {
|
||||||
|
"name": "grammar_progress_child_user_id_user_id_fk",
|
||||||
|
"tableFrom": "grammar_progress",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"child_user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"grammar_progress_id": {
|
||||||
|
"name": "grammar_progress_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"photo": {
|
||||||
|
"name": "photo",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"task_instance_id": {
|
||||||
|
"name": "task_instance_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"oss_key": {
|
||||||
|
"name": "oss_key",
|
||||||
|
"type": "varchar(300)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_photo_instance": {
|
||||||
|
"name": "idx_photo_instance",
|
||||||
|
"columns": [
|
||||||
|
"task_instance_id"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"photo_task_instance_id_task_instance_id_fk": {
|
||||||
|
"name": "photo_task_instance_id_task_instance_id_fk",
|
||||||
|
"tableFrom": "photo",
|
||||||
|
"tableTo": "task_instance",
|
||||||
|
"columnsFrom": [
|
||||||
|
"task_instance_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"photo_id": {
|
||||||
|
"name": "photo_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"session": {
|
||||||
|
"name": "session",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"token_hash": {
|
||||||
|
"name": "token_hash",
|
||||||
|
"type": "varchar(64)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"device_label": {
|
||||||
|
"name": "device_label",
|
||||||
|
"type": "varchar(100)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
},
|
||||||
|
"expires_at": {
|
||||||
|
"name": "expires_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"uq_session_token": {
|
||||||
|
"name": "uq_session_token",
|
||||||
|
"columns": [
|
||||||
|
"token_hash"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
},
|
||||||
|
"idx_session_user": {
|
||||||
|
"name": "idx_session_user",
|
||||||
|
"columns": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"session_user_id_user_id_fk": {
|
||||||
|
"name": "session_user_id_user_id_fk",
|
||||||
|
"tableFrom": "session",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"session_id": {
|
||||||
|
"name": "session_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"task_instance": {
|
||||||
|
"name": "task_instance",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"child_user_id": {
|
||||||
|
"name": "child_user_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"name": "date",
|
||||||
|
"type": "date",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "varchar(100)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"name": "subject",
|
||||||
|
"type": "enum('chinese','math','english','exercise','other')",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'other'"
|
||||||
|
},
|
||||||
|
"requires_photo": {
|
||||||
|
"name": "requires_photo",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"name": "status",
|
||||||
|
"type": "enum('pending','done')",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'pending'"
|
||||||
|
},
|
||||||
|
"is_makeup": {
|
||||||
|
"name": "is_makeup",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"done_at": {
|
||||||
|
"name": "done_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"sort_order": {
|
||||||
|
"name": "sort_order",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"source_template_id": {
|
||||||
|
"name": "source_template_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_instance_child_date": {
|
||||||
|
"name": "idx_instance_child_date",
|
||||||
|
"columns": [
|
||||||
|
"child_user_id",
|
||||||
|
"date"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"task_instance_child_user_id_user_id_fk": {
|
||||||
|
"name": "task_instance_child_user_id_user_id_fk",
|
||||||
|
"tableFrom": "task_instance",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"child_user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"task_instance_id": {
|
||||||
|
"name": "task_instance_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"task_template": {
|
||||||
|
"name": "task_template",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"child_user_id": {
|
||||||
|
"name": "child_user_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"dow": {
|
||||||
|
"name": "dow",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"name": "title",
|
||||||
|
"type": "varchar(100)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"subject": {
|
||||||
|
"name": "subject",
|
||||||
|
"type": "enum('chinese','math','english','exercise','other')",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "'other'"
|
||||||
|
},
|
||||||
|
"requires_photo": {
|
||||||
|
"name": "requires_photo",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"sort_order": {
|
||||||
|
"name": "sort_order",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"idx_template_child_dow": {
|
||||||
|
"name": "idx_template_child_dow",
|
||||||
|
"columns": [
|
||||||
|
"child_user_id",
|
||||||
|
"dow"
|
||||||
|
],
|
||||||
|
"isUnique": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"task_template_child_user_id_user_id_fk": {
|
||||||
|
"name": "task_template_child_user_id_user_id_fk",
|
||||||
|
"tableFrom": "task_template",
|
||||||
|
"tableTo": "user",
|
||||||
|
"columnsFrom": [
|
||||||
|
"child_user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "cascade",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"task_template_id": {
|
||||||
|
"name": "task_template_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"name": "user",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": true
|
||||||
|
},
|
||||||
|
"family_id": {
|
||||||
|
"name": "family_id",
|
||||||
|
"type": "bigint",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"role": {
|
||||||
|
"name": "role",
|
||||||
|
"type": "enum('parent','child')",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"display_name": {
|
||||||
|
"name": "display_name",
|
||||||
|
"type": "varchar(50)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"phone": {
|
||||||
|
"name": "phone",
|
||||||
|
"type": "varchar(20)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"password_hash": {
|
||||||
|
"name": "password_hash",
|
||||||
|
"type": "varchar(100)",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"autoincrement": false
|
||||||
|
},
|
||||||
|
"sort_order": {
|
||||||
|
"name": "sort_order",
|
||||||
|
"type": "int",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"name": "created_at",
|
||||||
|
"type": "datetime",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "CURRENT_TIMESTAMP"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {
|
||||||
|
"uq_user_phone": {
|
||||||
|
"name": "uq_user_phone",
|
||||||
|
"columns": [
|
||||||
|
"phone"
|
||||||
|
],
|
||||||
|
"isUnique": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foreignKeys": {
|
||||||
|
"user_family_id_family_id_fk": {
|
||||||
|
"name": "user_family_id_family_id_fk",
|
||||||
|
"tableFrom": "user",
|
||||||
|
"tableTo": "family",
|
||||||
|
"columnsFrom": [
|
||||||
|
"family_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"columns": [
|
||||||
|
"id"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uniqueConstraints": {},
|
||||||
|
"checkConstraint": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"views": {},
|
||||||
|
"_meta": {
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {},
|
||||||
|
"columns": {}
|
||||||
|
},
|
||||||
|
"internal": {
|
||||||
|
"tables": {},
|
||||||
|
"indexes": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,20 @@
|
|||||||
"when": 1785682170922,
|
"when": 1785682170922,
|
||||||
"tag": "0000_init",
|
"tag": "0000_init",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 1,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1785687829667,
|
||||||
|
"tag": "0001_add-subject",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 2,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1785689264881,
|
||||||
|
"tag": "0002_grammar-progress",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Generated
+10
@@ -8,6 +8,7 @@
|
|||||||
"name": "superjump",
|
"name": "superjump",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource-variable/plus-jakarta-sans": "^5.3.0",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
@@ -981,6 +982,15 @@
|
|||||||
"integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
|
"integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@fontsource-variable/plus-jakarta-sans": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@fontsource-variable/plus-jakarta-sans/-/plus-jakarta-sans-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-/l/4r0yyWK9JzAlmA0LiYgGgmJe/Gswt4jTJEzr5QhJfwMbvJZDmYWyW0M4X7yCK69BajMVlV/Lx8g7WDc1+sw==",
|
||||||
|
"license": "OFL-1.1",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ayuhito"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@img/colour": {
|
"node_modules/@img/colour": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@img/colour/-/colour-1.1.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@img/colour/-/colour-1.1.0.tgz",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"db:seed": "tsx scripts/seed.ts"
|
"db:seed": "tsx scripts/seed.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource-variable/plus-jakarta-sans": "^5.3.0",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
|||||||
+50
-20
@@ -1,4 +1,5 @@
|
|||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
|
@import "@fontsource-variable/plus-jakarta-sans";
|
||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
@@ -25,28 +26,41 @@
|
|||||||
--radius-md: calc(var(--radius) - 2px);
|
--radius-md: calc(var(--radius) - 2px);
|
||||||
--radius-lg: var(--radius);
|
--radius-lg: var(--radius);
|
||||||
--radius-xl: calc(var(--radius) + 4px);
|
--radius-xl: calc(var(--radius) + 4px);
|
||||||
|
|
||||||
|
/* 品牌字体:拉丁用 Plus Jakarta Sans,中文回落系统字体 */
|
||||||
|
--font-sans: "Plus Jakarta Sans Variable", "PingFang SC", "Hiragino Sans GB",
|
||||||
|
"Microsoft YaHei", system-ui, sans-serif;
|
||||||
|
|
||||||
|
/* 带色阴影(企业信任风的核心视觉签名) */
|
||||||
|
--shadow-soft: 0 4px 20px -2px rgb(79 70 229 / 0.1);
|
||||||
|
--shadow-lift: 0 10px 25px -5px rgb(79 70 229 / 0.15),
|
||||||
|
0 8px 10px -6px rgb(79 70 229 / 0.1);
|
||||||
|
--shadow-btn: 0 4px 14px 0 rgb(79 70 229 / 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Corporate Trust 色板:靛蓝主色 + 紫罗兰辅色 + 冷灰中性色 */
|
||||||
:root {
|
:root {
|
||||||
--radius: 0.625rem;
|
--radius: 0.75rem;
|
||||||
--background: oklch(1 0 0);
|
--background: #f8fafc; /* slate-50 */
|
||||||
--foreground: oklch(0.145 0 0);
|
--foreground: #0f172a; /* slate-900 */
|
||||||
--card: oklch(1 0 0);
|
--card: #ffffff;
|
||||||
--card-foreground: oklch(0.145 0 0);
|
--card-foreground: #0f172a;
|
||||||
--popover: oklch(1 0 0);
|
--popover: #ffffff;
|
||||||
--popover-foreground: oklch(0.145 0 0);
|
--popover-foreground: #0f172a;
|
||||||
--primary: oklch(0.205 0 0);
|
--primary: #4f46e5; /* indigo-600 */
|
||||||
--primary-foreground: oklch(0.985 0 0);
|
--primary-foreground: #ffffff;
|
||||||
--secondary: oklch(0.97 0 0);
|
--secondary: #f1f5f9; /* slate-100 */
|
||||||
--secondary-foreground: oklch(0.205 0 0);
|
--secondary-foreground: #334155; /* slate-700 */
|
||||||
--muted: oklch(0.97 0 0);
|
--muted: #f1f5f9;
|
||||||
--muted-foreground: oklch(0.556 0 0);
|
--muted-foreground: #64748b; /* slate-500 */
|
||||||
--accent: oklch(0.97 0 0);
|
--accent: #eef2ff; /* indigo-50 */
|
||||||
--accent-foreground: oklch(0.205 0 0);
|
--accent-foreground: #4f46e5;
|
||||||
--destructive: oklch(0.577 0.245 27.325);
|
--destructive: #ef4444;
|
||||||
--border: oklch(0.922 0 0);
|
--border: #e2e8f0; /* slate-200 */
|
||||||
--input: oklch(0.922 0 0);
|
--input: #e2e8f0;
|
||||||
--ring: oklch(0.708 0 0);
|
--ring: #6366f1; /* indigo-500 */
|
||||||
|
--violet: #7c3aed; /* violet-600,渐变辅色 */
|
||||||
|
--emerald: #10b981; /* 成功色 */
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
@@ -54,6 +68,22 @@
|
|||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground font-sans antialiased;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 渐变文字:靛蓝 → 紫罗兰,用于重点标题 */
|
||||||
|
@utility text-gradient {
|
||||||
|
background-image: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 背景氛围光斑:大号模糊渐变圆,营造纵深 */
|
||||||
|
@utility bg-blob {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 9999px;
|
||||||
|
filter: blur(64px);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|||||||
+14
-8
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
import { useActionState } from "react";
|
import { useActionState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { KeyRound } from "lucide-react";
|
||||||
|
import { BackgroundBlobs } from "@/components/background-blobs";
|
||||||
import { activate } from "./actions";
|
import { activate } from "./actions";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
|
||||||
@@ -12,12 +14,16 @@ export default function JoinPage() {
|
|||||||
const [state, formAction, pending] = useActionState(activate, null);
|
const [state, formAction, pending] = useActionState(activate, null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-dvh items-center justify-center bg-muted/40 p-4">
|
<main className="relative flex min-h-dvh items-center justify-center p-4">
|
||||||
<Card className="w-full max-w-sm">
|
<BackgroundBlobs />
|
||||||
<CardHeader className="text-center">
|
<Card className="w-full max-w-sm border-slate-100 shadow-soft transition-shadow duration-200 hover:shadow-lift">
|
||||||
<CardTitle className="text-2xl">激活这台设备</CardTitle>
|
<CardHeader className="items-center gap-3 text-center">
|
||||||
|
<div className="flex size-14 items-center justify-center rounded-xl bg-gradient-to-br from-indigo-600 to-violet-600 shadow-btn">
|
||||||
|
<KeyRound className="size-7 text-white" />
|
||||||
|
</div>
|
||||||
|
<h1 className="text-2xl font-extrabold tracking-tight">激活这台设备</h1>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
请让家长在家长端生成激活码,然后输入下面的框里
|
请让家长在家长端生成激活码,输入下面的框里
|
||||||
</p>
|
</p>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@@ -32,7 +38,7 @@ export default function JoinPage() {
|
|||||||
pattern="\d{6}"
|
pattern="\d{6}"
|
||||||
maxLength={6}
|
maxLength={6}
|
||||||
autoComplete="one-time-code"
|
autoComplete="one-time-code"
|
||||||
className="text-center text-3xl tracking-[0.5em] font-bold"
|
className="text-center text-3xl font-bold tracking-[0.5em] text-indigo-600"
|
||||||
placeholder="······"
|
placeholder="······"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
@@ -47,7 +53,7 @@ export default function JoinPage() {
|
|||||||
我是家长,{" "}
|
我是家长,{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/login"
|
href="/login"
|
||||||
className="font-medium text-primary underline-offset-4 hover:underline"
|
className="font-semibold text-indigo-600 underline-offset-4 hover:underline"
|
||||||
>
|
>
|
||||||
去登录
|
去登录
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
+68
-18
@@ -1,9 +1,15 @@
|
|||||||
import { Flame } from "lucide-react";
|
import { BookOpen, Flame } from "lucide-react";
|
||||||
|
import Link from "next/link";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
|
import { BackgroundBlobs } from "@/components/background-blobs";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { SUBJECT_ORDER, subjectMeta } from "@/lib/subjects";
|
||||||
import { todayStr } from "@/lib/dates";
|
import { todayStr } from "@/lib/dates";
|
||||||
import { getSessionUser } from "@/lib/auth";
|
import { getSessionUser } from "@/lib/auth";
|
||||||
import { streakOf } from "@/lib/streak";
|
import { streakOf } from "@/lib/streak";
|
||||||
import { dayTasks } from "@/lib/tasks";
|
import { dayTasks } from "@/lib/tasks";
|
||||||
|
import { entryBySeq, TOTAL } from "@/content/grammar";
|
||||||
|
import { nextSeq, passedSet } from "@/lib/grammar";
|
||||||
import { TaskCard } from "./task-card";
|
import { TaskCard } from "./task-card";
|
||||||
|
|
||||||
export default async function KidPage() {
|
export default async function KidPage() {
|
||||||
@@ -19,40 +25,84 @@ export default async function KidPage() {
|
|||||||
const doneCount = tasks.filter((t) => t.status === "done").length;
|
const doneCount = tasks.filter((t) => t.status === "done").length;
|
||||||
const allDone = tasks.length > 0 && doneCount === tasks.length;
|
const allDone = tasks.length > 0 && doneCount === tasks.length;
|
||||||
|
|
||||||
|
// 英语语法入口:下一课标题 + 已完成课数
|
||||||
|
const gNext = await nextSeq(user.id);
|
||||||
|
const gGoal = gNext <= TOTAL ? entryBySeq(gNext) : null;
|
||||||
|
const gDone = (await passedSet(user.id)).size;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="mx-auto max-w-lg space-y-5 p-4 pb-10">
|
<main className="relative mx-auto max-w-lg space-y-5 p-4 pb-10">
|
||||||
|
<BackgroundBlobs />
|
||||||
<header className="flex items-center justify-between">
|
<header className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h1 className="text-2xl font-bold">你好,{user.displayName}</h1>
|
<h1 className="text-2xl font-extrabold tracking-tight">
|
||||||
|
你好,<span className="text-gradient">{user.displayName}</span>
|
||||||
|
</h1>
|
||||||
<p className="text-sm text-muted-foreground">{today}</p>
|
<p className="text-sm text-muted-foreground">{today}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1 rounded-full bg-orange-100 px-4 py-2 text-orange-600">
|
<div className="flex items-center gap-1.5 rounded-full bg-gradient-to-r from-amber-400 to-orange-500 px-4 py-2 text-white shadow-[0_4px_14px_0_rgba(249,115,22,0.35)]">
|
||||||
<Flame className="size-6" fill="currentColor" />
|
<Flame className="size-5" fill="currentColor" />
|
||||||
<span className="text-xl font-bold">{streak}</span>
|
<span className="text-xl font-extrabold">{streak}</span>
|
||||||
<span className="text-sm">天</span>
|
<span className="text-xs font-medium">天</span>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<Link href="/learn" className="block">
|
||||||
|
<div className="flex items-center gap-3 rounded-xl bg-gradient-to-r from-indigo-600 to-violet-600 p-4 text-white shadow-btn transition-transform duration-200 hover:-translate-y-0.5">
|
||||||
|
<div className="flex size-11 shrink-0 items-center justify-center rounded-lg bg-white/20">
|
||||||
|
<BookOpen className="size-6" />
|
||||||
|
</div>
|
||||||
|
<div className="min-w-0 flex-1">
|
||||||
|
<p className="text-xs font-medium opacity-90">英语语法 · 已学 {gDone} 课</p>
|
||||||
|
<p className="truncate text-base font-bold">
|
||||||
|
{gGoal ? gGoal.title : "全部完成,真棒!"}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<span className="shrink-0 text-lg">→</span>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
|
||||||
{tasks.length === 0 ? (
|
{tasks.length === 0 ? (
|
||||||
<div className="rounded-2xl bg-muted p-8 text-center">
|
<div className="rounded-xl border border-slate-100 bg-white p-8 text-center shadow-soft">
|
||||||
<p className="text-2xl">🎉</p>
|
<p className="text-3xl">🎉</p>
|
||||||
<p className="mt-2 text-lg font-medium">今天没有任务</p>
|
<p className="mt-2 text-lg font-bold">今天没有任务</p>
|
||||||
<p className="mt-1 text-sm text-muted-foreground">连击自动保持,去玩吧!</p>
|
<p className="mt-1 text-sm text-muted-foreground">连击自动保持,去玩吧!</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm font-medium text-muted-foreground">
|
||||||
已完成 {doneCount} / {tasks.length} 项
|
已完成{" "}
|
||||||
|
<span className="text-base font-extrabold text-indigo-600">{doneCount}</span> /{" "}
|
||||||
|
{tasks.length} 项
|
||||||
</p>
|
</p>
|
||||||
<div className="space-y-3">
|
<div className="space-y-4">
|
||||||
{tasks.map((t) => (
|
{SUBJECT_ORDER.map((key) => {
|
||||||
<TaskCard key={t.id} task={t} />
|
const group = tasks.filter((t) => t.subject === key);
|
||||||
))}
|
if (group.length === 0) return null;
|
||||||
|
const meta = subjectMeta(key);
|
||||||
|
const gDone = group.filter((t) => t.status === "done").length;
|
||||||
|
return (
|
||||||
|
<section key={key} className="space-y-2">
|
||||||
|
<header className="flex items-center gap-2 px-1">
|
||||||
|
<span className={cn("size-2.5 rounded-full", meta.dot)} />
|
||||||
|
<span className={cn("text-sm font-bold", meta.text)}>{meta.label}</span>
|
||||||
|
<span className="text-xs text-muted-foreground">
|
||||||
|
{gDone}/{group.length}
|
||||||
|
</span>
|
||||||
|
</header>
|
||||||
|
<div className="space-y-3">
|
||||||
|
{group.map((t) => (
|
||||||
|
<TaskCard key={t.id} task={t} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
{allDone && (
|
{allDone && (
|
||||||
<div className="rounded-2xl bg-green-100 p-6 text-center">
|
<div className="rounded-xl bg-gradient-to-r from-indigo-600 to-violet-600 p-6 text-center text-white shadow-btn">
|
||||||
<p className="text-2xl">💪</p>
|
<p className="text-2xl">💪</p>
|
||||||
<p className="mt-2 text-lg font-bold text-green-700">今天全部完成,太棒了!</p>
|
<p className="mt-2 text-lg font-extrabold">今天全部完成,太棒了!</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -77,8 +77,8 @@ export function TaskCard({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`rounded-2xl border-2 p-4 transition-colors ${
|
className={`rounded-xl border bg-white p-4 shadow-soft transition-all duration-200 hover:shadow-lift ${
|
||||||
done ? "border-green-500 bg-green-50" : "border-border bg-card"
|
done ? "border-emerald-200 bg-emerald-50/60" : "border-slate-100"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
@@ -87,26 +87,36 @@ export function TaskCard({
|
|||||||
onClick={onToggle}
|
onClick={onToggle}
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
aria-label={done ? "取消完成" : "标记完成"}
|
aria-label={done ? "取消完成" : "标记完成"}
|
||||||
className={`flex size-12 shrink-0 items-center justify-center rounded-full border-2 transition-colors ${
|
className={`flex size-12 shrink-0 items-center justify-center rounded-full border-2 transition-all duration-200 ${
|
||||||
done ? "border-green-500 bg-green-500 text-white" : "border-muted-foreground/40"
|
done
|
||||||
|
? "border-transparent bg-gradient-to-br from-emerald-400 to-emerald-600 text-white shadow-[0_0_16px_rgba(16,185,129,0.4)]"
|
||||||
|
: "border-slate-300 hover:border-indigo-400"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{done && <Check className="size-7" strokeWidth={3} />}
|
{done && <Check className="size-7" strokeWidth={3} />}
|
||||||
</button>
|
</button>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<p className={`text-lg font-medium ${done ? "text-green-700 line-through" : ""}`}>
|
<p
|
||||||
|
className={`text-lg font-semibold ${
|
||||||
|
done ? "text-emerald-700 line-through" : "text-slate-900"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{task.title}
|
{task.title}
|
||||||
</p>
|
</p>
|
||||||
<div className="mt-1 flex items-center gap-2 text-sm text-muted-foreground">
|
<div className="mt-1 flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
{task.requiresPhoto && <Camera className="size-4" />}
|
{task.requiresPhoto && <Camera className="size-4" />}
|
||||||
{task.requiresPhoto && <span>需拍照凭证</span>}
|
{task.requiresPhoto && <span>需拍照凭证</span>}
|
||||||
{task.isMakeup && <span className="text-orange-500">补卡</span>}
|
{task.isMakeup && (
|
||||||
|
<span className="rounded-full bg-amber-100 px-2 py-0.5 text-xs font-semibold text-amber-600">
|
||||||
|
补卡
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{task.requiresPhoto && task.photoUrls.length < 3 && (
|
{task.requiresPhoto && task.photoUrls.length < 3 && (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="outline"
|
variant="secondary"
|
||||||
size="sm"
|
size="sm"
|
||||||
disabled={busy}
|
disabled={busy}
|
||||||
onClick={() => fileRef.current?.click()}
|
onClick={() => fileRef.current?.click()}
|
||||||
@@ -132,7 +142,7 @@ export function TaskCard({
|
|||||||
key={url}
|
key={url}
|
||||||
src={url}
|
src={url}
|
||||||
alt="凭证照片"
|
alt="凭证照片"
|
||||||
className="size-16 rounded-lg border object-cover"
|
className="size-16 rounded-lg border border-slate-100 object-cover shadow-xs"
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+1
-2
@@ -17,9 +17,8 @@ export default function RootLayout({
|
|||||||
children,
|
children,
|
||||||
}: Readonly<{ children: React.ReactNode }>) {
|
}: Readonly<{ children: React.ReactNode }>) {
|
||||||
return (
|
return (
|
||||||
// 系统字体栈,不加载任何网络字体(避免构建与访问时请求境外服务)
|
|
||||||
<html lang="zh-CN">
|
<html lang="zh-CN">
|
||||||
<body className="min-h-dvh antialiased">{children}</body>
|
<body className="min-h-dvh">{children}</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { BackgroundBlobs } from "@/components/background-blobs";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { CEFR_STYLE } from "@/lib/cefr";
|
||||||
|
import { TOTAL, entryBySeq } from "@/content/grammar";
|
||||||
|
import { isUnlocked, passedSet } from "@/lib/grammar";
|
||||||
|
import { getSessionUser } from "@/lib/auth";
|
||||||
|
import { SectionBlock } from "../section-block";
|
||||||
|
import { Practice } from "../practice";
|
||||||
|
import { QuizForm } from "../quiz-form";
|
||||||
|
|
||||||
|
export default async function LessonPage({ params }: { params: Promise<{ seq: string }> }) {
|
||||||
|
const user = await getSessionUser();
|
||||||
|
if (!user) redirect("/join");
|
||||||
|
if (user.role !== "child") redirect("/parent");
|
||||||
|
|
||||||
|
const seq = Number((await params).seq);
|
||||||
|
const entry = entryBySeq(seq);
|
||||||
|
if (!entry) redirect("/learn");
|
||||||
|
|
||||||
|
const passed = await passedSet(user.id);
|
||||||
|
if (!isUnlocked(seq, passed)) redirect("/learn");
|
||||||
|
|
||||||
|
const alreadyPassed = passed.has(seq);
|
||||||
|
const nextSeq = seq < TOTAL ? seq + 1 : null;
|
||||||
|
const cefr = CEFR_STYLE[entry.cefr];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="relative mx-auto max-w-2xl space-y-6 p-4 pb-12">
|
||||||
|
<BackgroundBlobs />
|
||||||
|
<header className="space-y-2">
|
||||||
|
<Link href="/learn" className="text-sm font-medium text-indigo-600">
|
||||||
|
← 课程地图
|
||||||
|
</Link>
|
||||||
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
|
<span className={cn("rounded-full px-3 py-1 text-xs font-semibold", cefr.cls)}>
|
||||||
|
{cefr.label}
|
||||||
|
</span>
|
||||||
|
<Badge variant="secondary">
|
||||||
|
{entry.type === "lesson" ? `第 ${seq} 课` : entry.type === "weekly" ? "周测" : "月测"}
|
||||||
|
</Badge>
|
||||||
|
{alreadyPassed && (
|
||||||
|
<Badge className="bg-emerald-100 text-emerald-700 hover:bg-emerald-100">已通过</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<h1 className="text-2xl font-extrabold tracking-tight text-slate-900">{entry.title}</h1>
|
||||||
|
{entry.type === "lesson" ? (
|
||||||
|
<p className="text-indigo-600">🎯 {entry.goal}</p>
|
||||||
|
) : (
|
||||||
|
<p className="text-slate-600">{entry.intro}</p>
|
||||||
|
)}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{entry.type === "lesson" && (
|
||||||
|
<>
|
||||||
|
<div className="space-y-8 rounded-2xl border border-slate-100 bg-white p-5 shadow-soft">
|
||||||
|
{entry.sections.map((s, i) => (
|
||||||
|
<SectionBlock key={i} s={s} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<Practice items={entry.practice} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="rounded-2xl border border-slate-100 bg-white p-5 shadow-soft">
|
||||||
|
<QuizForm seq={seq} quiz={entry.quiz} nextSeq={nextSeq} alreadyPassed={alreadyPassed} />
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import { getSessionUser } from "@/lib/auth";
|
||||||
|
import { entryBySeq } from "@/content/grammar";
|
||||||
|
import { completeSeq, grade, isUnlocked, passedSet } from "@/lib/grammar";
|
||||||
|
|
||||||
|
export type QuizResult =
|
||||||
|
| {
|
||||||
|
score: number;
|
||||||
|
passed: boolean;
|
||||||
|
correct: number;
|
||||||
|
total: number;
|
||||||
|
detail: boolean[];
|
||||||
|
}
|
||||||
|
| { error: string };
|
||||||
|
|
||||||
|
// 提交测验:服务端按标准答案计分(防篡改),达标即记进度并联动英语打卡
|
||||||
|
export async function submitQuiz(_prev: QuizResult | null, formData: FormData): Promise<QuizResult> {
|
||||||
|
const user = await getSessionUser();
|
||||||
|
if (!user || user.role !== "child") return { error: "会话无效,请重新激活设备" };
|
||||||
|
|
||||||
|
const seq = Number(formData.get("seq"));
|
||||||
|
const entry = entryBySeq(seq);
|
||||||
|
if (!entry) return { error: "课程不存在" };
|
||||||
|
|
||||||
|
const passed = await passedSet(user.id);
|
||||||
|
if (!isUnlocked(seq, passed)) return { error: "请先完成前面的课程" };
|
||||||
|
|
||||||
|
const answers = entry.quiz.map((_, i) => Number(formData.get(`a${i}`)));
|
||||||
|
const g = grade(entry.quiz, answers);
|
||||||
|
|
||||||
|
await completeSeq(user.id, seq, g.score, g.passed);
|
||||||
|
revalidatePath("/learn");
|
||||||
|
revalidatePath(`/learn/${seq}`);
|
||||||
|
revalidatePath("/kid");
|
||||||
|
revalidatePath("/parent");
|
||||||
|
return g;
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import { BookOpen, Check, Lock } from "lucide-react";
|
||||||
|
import { redirect } from "next/navigation";
|
||||||
|
import { BackgroundBlobs } from "@/components/background-blobs";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { CEFR_STYLE } from "@/lib/cefr";
|
||||||
|
import { SYLLABUS, TOTAL, entryBySeq } from "@/content/grammar";
|
||||||
|
import { isUnlocked, nextSeq, passedSet } from "@/lib/grammar";
|
||||||
|
import { getSessionUser } from "@/lib/auth";
|
||||||
|
|
||||||
|
export default async function LearnHome() {
|
||||||
|
const user = await getSessionUser();
|
||||||
|
if (!user) redirect("/join");
|
||||||
|
if (user.role !== "child") redirect("/parent");
|
||||||
|
|
||||||
|
const passed = await passedSet(user.id);
|
||||||
|
const done = passed.size;
|
||||||
|
const next = await nextSeq(user.id);
|
||||||
|
const current = next <= TOTAL ? entryBySeq(next) : null;
|
||||||
|
const pct = Math.round((done / TOTAL) * 100);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className="relative mx-auto max-w-lg space-y-5 p-4 pb-10">
|
||||||
|
<BackgroundBlobs />
|
||||||
|
<header className="flex items-center justify-between">
|
||||||
|
<Link href="/kid" className="text-sm font-medium text-indigo-600">
|
||||||
|
← 返回打卡
|
||||||
|
</Link>
|
||||||
|
<span className="text-sm text-muted-foreground">
|
||||||
|
{done} / {TOTAL} 课
|
||||||
|
</span>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{current ? (
|
||||||
|
<div className="rounded-2xl bg-gradient-to-br from-indigo-600 to-violet-600 p-6 text-white shadow-btn">
|
||||||
|
<span className="inline-block rounded-full bg-white/20 px-3 py-1 text-xs font-semibold">
|
||||||
|
今日目标 · 第 {current.seq} 课
|
||||||
|
</span>
|
||||||
|
<h1 className="mt-3 text-2xl font-extrabold leading-tight">{current.title}</h1>
|
||||||
|
<p className="mt-1 text-sm opacity-90">
|
||||||
|
{current.type === "lesson" ? current.goal : current.intro}
|
||||||
|
</p>
|
||||||
|
<Link href={`/learn/${current.seq}`} className="mt-4 block">
|
||||||
|
<Button variant="secondary" size="lg" className="w-full">
|
||||||
|
{done === 0 ? "开始第一课" : "继续学习"} →
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="rounded-2xl bg-gradient-to-br from-emerald-500 to-emerald-600 p-6 text-center text-white shadow-btn">
|
||||||
|
<p className="text-3xl">🏆</p>
|
||||||
|
<p className="mt-2 text-xl font-extrabold">语法课程全部完成!</p>
|
||||||
|
<p className="mt-1 text-sm opacity-90">太厉害了,继续保持每天复习。</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="rounded-xl border border-slate-100 bg-white p-4 shadow-soft">
|
||||||
|
<div className="mb-1 flex justify-between text-sm">
|
||||||
|
<span className="font-medium text-slate-700">总进度</span>
|
||||||
|
<span className="font-bold text-indigo-600">{pct}%</span>
|
||||||
|
</div>
|
||||||
|
<div className="h-2.5 w-full overflow-hidden rounded-full bg-slate-100">
|
||||||
|
<div
|
||||||
|
className="h-full rounded-full bg-gradient-to-r from-indigo-500 to-violet-500 transition-all"
|
||||||
|
style={{ width: `${pct}%` }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-7 gap-2">
|
||||||
|
{SYLLABUS.map((e) => {
|
||||||
|
const doneIt = passed.has(e.seq);
|
||||||
|
const cur = e.seq === next;
|
||||||
|
const unlocked = isUnlocked(e.seq, passed);
|
||||||
|
const isMilestone = e.type !== "lesson";
|
||||||
|
const inner = (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"flex aspect-square items-center justify-center rounded-lg text-xs font-bold transition-colors",
|
||||||
|
doneIt && "bg-gradient-to-br from-emerald-400 to-emerald-600 text-white shadow-[0_0_12px_rgba(16,185,129,0.4)]",
|
||||||
|
!doneIt && cur && "bg-gradient-to-br from-indigo-500 to-violet-600 text-white ring-2 ring-indigo-300",
|
||||||
|
!doneIt && !cur && unlocked && "border border-slate-200 bg-white text-slate-500",
|
||||||
|
!doneIt && !unlocked && "bg-slate-100 text-slate-300",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{doneIt ? (
|
||||||
|
<Check className="size-4" strokeWidth={3} />
|
||||||
|
) : !unlocked ? (
|
||||||
|
<Lock className="size-3.5" />
|
||||||
|
) : isMilestone ? (
|
||||||
|
<BookOpen className="size-3.5" />
|
||||||
|
) : (
|
||||||
|
e.seq
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
const style = e.type === "lesson" ? "" : "ring-1 ring-amber-200";
|
||||||
|
return unlocked ? (
|
||||||
|
<Link key={e.seq} href={`/learn/${e.seq}`} className={style} title={e.title}>
|
||||||
|
{inner}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<div key={e.seq} className={style} title={unlocked ? e.title : "未解锁"}>
|
||||||
|
{inner}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<p className="text-center text-xs text-muted-foreground">
|
||||||
|
方块带书图标的是周测/月测;灰锁需先通过前一课
|
||||||
|
</p>
|
||||||
|
<p className="text-center text-xs text-muted-foreground">
|
||||||
|
级别:{[...new Set(SYLLABUS.map((e) => e.cefr))].map((c) => (
|
||||||
|
<span key={c} className={cn("mx-0.5 rounded px-1.5 py-0.5", CEFR_STYLE[c].cls)}>
|
||||||
|
{c}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</p>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Check, X } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { QuizQ } from "@/content/grammar/types";
|
||||||
|
|
||||||
|
// 课内随练:点选后立即显示对错与解析,不计分
|
||||||
|
export function Practice({ items }: { items: QuizQ[] }) {
|
||||||
|
const [picked, setPicked] = useState<(number | null)[]>(items.map(() => null));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-3">
|
||||||
|
<h3 className="text-base font-bold text-slate-900">练一练</h3>
|
||||||
|
{items.map((q, qi) => {
|
||||||
|
const p = picked[qi];
|
||||||
|
const revealed = p !== null;
|
||||||
|
return (
|
||||||
|
<div key={qi} className="rounded-xl border border-slate-100 bg-white p-4 shadow-soft">
|
||||||
|
<p className="font-medium text-slate-900">
|
||||||
|
{qi + 1}. {q.q}
|
||||||
|
</p>
|
||||||
|
<div className="mt-2 space-y-1.5">
|
||||||
|
{q.options.map((opt, oi) => {
|
||||||
|
const isRight = revealed && oi === q.answer;
|
||||||
|
const isWrong = revealed && oi === p && oi !== q.answer;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={oi}
|
||||||
|
type="button"
|
||||||
|
disabled={revealed}
|
||||||
|
onClick={() => {
|
||||||
|
const next = [...picked];
|
||||||
|
next[qi] = oi;
|
||||||
|
setPicked(next);
|
||||||
|
}}
|
||||||
|
className={cn(
|
||||||
|
"flex w-full items-center gap-2 rounded-lg border px-3 py-2 text-left text-sm transition-colors",
|
||||||
|
!revealed && "border-slate-200 hover:border-indigo-300 hover:bg-indigo-50/50",
|
||||||
|
isRight && "border-emerald-300 bg-emerald-50 text-emerald-700",
|
||||||
|
isWrong && "border-rose-300 bg-rose-50 text-rose-700",
|
||||||
|
revealed && !isRight && !isWrong && "border-slate-100 text-slate-400",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{isRight && <Check className="size-4 shrink-0" />}
|
||||||
|
{isWrong && <X className="size-4 shrink-0" />}
|
||||||
|
<span>{opt}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{revealed && (
|
||||||
|
<p className="mt-2 text-sm text-muted-foreground">
|
||||||
|
解析:{q.explain}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setPicked(items.map(() => null))}
|
||||||
|
>
|
||||||
|
重做练习
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useActionState, useState } from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { CheckCircle2, XCircle } from "lucide-react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { QuizQ } from "@/content/grammar/types";
|
||||||
|
import { submitQuiz, type QuizResult } from "./actions";
|
||||||
|
|
||||||
|
// 计分测验:选中后提交,服务端判分;达标才算通过并解锁下一课
|
||||||
|
export function QuizForm({
|
||||||
|
seq,
|
||||||
|
quiz,
|
||||||
|
nextSeq,
|
||||||
|
alreadyPassed,
|
||||||
|
}: {
|
||||||
|
seq: number;
|
||||||
|
quiz: QuizQ[];
|
||||||
|
nextSeq: number | null;
|
||||||
|
alreadyPassed: boolean;
|
||||||
|
}) {
|
||||||
|
const [state, formAction, pending] = useActionState<QuizResult | null, FormData>(submitQuiz, null);
|
||||||
|
const [picked, setPicked] = useState<(number | null)[]>(quiz.map(() => null));
|
||||||
|
const result = state && "score" in state ? state : null;
|
||||||
|
const error = state && "error" in state ? state.error : null;
|
||||||
|
const allAnswered = picked.every((p) => p !== null);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<h3 className="text-base font-bold text-slate-900">
|
||||||
|
{alreadyPassed ? "再测一次" : "课后测验"}
|
||||||
|
<span className="ml-2 text-sm font-normal text-muted-foreground">
|
||||||
|
满分通过线 80%,达标即完成本课并自动打卡
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<form action={formAction} className="space-y-3">
|
||||||
|
<input type="hidden" name="seq" value={seq} />
|
||||||
|
{quiz.map((q, qi) => (
|
||||||
|
<div key={qi} className="rounded-xl border border-slate-100 bg-white p-4 shadow-soft">
|
||||||
|
<p className="font-medium text-slate-900">
|
||||||
|
{qi + 1}. {q.q}
|
||||||
|
</p>
|
||||||
|
<div className="mt-2 space-y-1.5">
|
||||||
|
{q.options.map((opt, oi) => {
|
||||||
|
const sel = picked[qi] === oi;
|
||||||
|
const isRight = result && oi === q.answer;
|
||||||
|
const isWrong = result && sel && oi !== q.answer;
|
||||||
|
return (
|
||||||
|
<label
|
||||||
|
key={oi}
|
||||||
|
className={cn(
|
||||||
|
"flex cursor-pointer items-center gap-2 rounded-lg border px-3 py-2 text-sm transition-colors",
|
||||||
|
!result && sel && "border-indigo-400 bg-indigo-50 ring-1 ring-indigo-300",
|
||||||
|
!result && !sel && "border-slate-200 hover:border-indigo-300",
|
||||||
|
isRight && "border-emerald-300 bg-emerald-50 text-emerald-700",
|
||||||
|
isWrong && "border-rose-300 bg-rose-50 text-rose-700",
|
||||||
|
result && !isRight && !isWrong && "border-slate-100 text-slate-400",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name={`a${qi}`}
|
||||||
|
value={oi}
|
||||||
|
checked={sel}
|
||||||
|
disabled={!!result}
|
||||||
|
onChange={() => {
|
||||||
|
const next = [...picked];
|
||||||
|
next[qi] = oi;
|
||||||
|
setPicked(next);
|
||||||
|
}}
|
||||||
|
className="sr-only"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
"flex size-4 shrink-0 items-center justify-center rounded-full border",
|
||||||
|
sel && !result && "border-indigo-500 bg-indigo-500",
|
||||||
|
!sel && !result && "border-slate-300",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{sel && !result && <span className="size-1.5 rounded-full bg-white" />}
|
||||||
|
</span>
|
||||||
|
<span>{opt}</span>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
{result && (
|
||||||
|
<p className="mt-2 text-sm text-muted-foreground">解析:{q.explain}</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{!result && (
|
||||||
|
<Button type="submit" size="lg" className="w-full" disabled={pending || !allAnswered}>
|
||||||
|
{pending ? "判分中…" : "提交测验"}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{error && <p className="text-sm font-medium text-destructive">{error}</p>}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{result && (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"rounded-xl p-5 text-center text-white shadow-btn",
|
||||||
|
result.passed
|
||||||
|
? "bg-gradient-to-r from-emerald-500 to-emerald-600"
|
||||||
|
: "bg-gradient-to-r from-rose-500 to-rose-600",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<p className="text-4xl font-extrabold">{result.score} 分</p>
|
||||||
|
<p className="mt-1 text-sm opacity-90">
|
||||||
|
答对 {result.correct} / {result.total}
|
||||||
|
{result.passed ? " · 通过 🎉" : " · 再复习一遍吧"}
|
||||||
|
</p>
|
||||||
|
<div className="mt-4 flex justify-center gap-3">
|
||||||
|
{!result.passed && (
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
onClick={() => {
|
||||||
|
setPicked(quiz.map(() => null));
|
||||||
|
// 触发重新挂载以清空结果:通过刷新页面最稳妥
|
||||||
|
window.location.reload();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
重做测验
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{result.passed && nextSeq && (
|
||||||
|
<Link href={`/learn/${nextSeq}`}>
|
||||||
|
<Button variant="secondary" size="lg">
|
||||||
|
下一课 →
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
{result.passed && !nextSeq && (
|
||||||
|
<Link href="/learn">
|
||||||
|
<Button variant="secondary" size="lg">
|
||||||
|
全部完成 🏆
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { renderBold } from "@/lib/md";
|
||||||
|
import type { Section } from "@/content/grammar/types";
|
||||||
|
|
||||||
|
// 渲染一个讲解小节:英文讲解 + 中文要点 + 例句 + 结构表 + 易错提示
|
||||||
|
export function SectionBlock({ s }: { s: Section }) {
|
||||||
|
return (
|
||||||
|
<section className="space-y-3">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-bold text-slate-900">{s.heading}</h3>
|
||||||
|
<p className="text-sm font-medium text-indigo-600">{s.zh}</p>
|
||||||
|
</div>
|
||||||
|
<p className="leading-relaxed text-slate-700">
|
||||||
|
{renderBold(s.body).map((part, i) =>
|
||||||
|
typeof part === "string" ? (
|
||||||
|
<span key={i}>{part}</span>
|
||||||
|
) : (
|
||||||
|
<strong key={i} className="font-semibold text-slate-900">
|
||||||
|
{part.b}
|
||||||
|
</strong>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{s.structure && (
|
||||||
|
<div className="overflow-hidden rounded-lg border border-slate-200">
|
||||||
|
<table className="w-full text-sm">
|
||||||
|
<thead className="bg-indigo-50 text-indigo-700">
|
||||||
|
<tr>
|
||||||
|
{s.structure.cols.map((c) => (
|
||||||
|
<th key={c} className="px-3 py-2 text-left font-semibold">
|
||||||
|
{c}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{s.structure.rows.map((row, ri) => (
|
||||||
|
<tr key={ri} className="border-t border-slate-100">
|
||||||
|
{row.map((cell, ci) => (
|
||||||
|
<td key={ci} className="px-3 py-2 text-slate-700">
|
||||||
|
{cell}
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{s.examples && (
|
||||||
|
<ul className="space-y-1 rounded-lg bg-slate-50 p-3">
|
||||||
|
{s.examples.map((ex, i) => (
|
||||||
|
<li key={i} className="flex gap-2 text-slate-700">
|
||||||
|
<span className="font-bold text-indigo-400">›</span>
|
||||||
|
<span>{ex}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{s.note && (
|
||||||
|
<p className="rounded-lg border-l-4 border-amber-400 bg-amber-50 px-3 py-2 text-sm text-amber-800">
|
||||||
|
💡 {s.note}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
+14
-6
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
import { useActionState } from "react";
|
import { useActionState } from "react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
import { GraduationCap } from "lucide-react";
|
||||||
|
import { BackgroundBlobs } from "@/components/background-blobs";
|
||||||
import { login } from "./actions";
|
import { login } from "./actions";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
|
||||||
@@ -12,10 +14,16 @@ export default function LoginPage() {
|
|||||||
const [state, formAction, pending] = useActionState(login, null);
|
const [state, formAction, pending] = useActionState(login, null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-dvh items-center justify-center bg-muted/40 p-4">
|
<main className="relative flex min-h-dvh items-center justify-center p-4">
|
||||||
<Card className="w-full max-w-sm">
|
<BackgroundBlobs />
|
||||||
<CardHeader className="text-center">
|
<Card className="w-full max-w-sm border-slate-100 shadow-soft transition-shadow duration-200 hover:shadow-lift">
|
||||||
<CardTitle className="text-3xl">SuperJump</CardTitle>
|
<CardHeader className="items-center gap-3 text-center">
|
||||||
|
<div className="flex size-14 items-center justify-center rounded-xl bg-gradient-to-br from-indigo-600 to-violet-600 shadow-btn">
|
||||||
|
<GraduationCap className="size-8 text-white" />
|
||||||
|
</div>
|
||||||
|
<h1 className="text-3xl font-extrabold tracking-tight">
|
||||||
|
Super<span className="text-gradient">Jump</span>
|
||||||
|
</h1>
|
||||||
<p className="text-sm text-muted-foreground">家长登录</p>
|
<p className="text-sm text-muted-foreground">家长登录</p>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
@@ -52,7 +60,7 @@ export default function LoginPage() {
|
|||||||
孩子的设备第一次使用?{" "}
|
孩子的设备第一次使用?{" "}
|
||||||
<Link
|
<Link
|
||||||
href="/join"
|
href="/join"
|
||||||
className="font-medium text-primary underline-offset-4 hover:underline"
|
className="font-semibold text-indigo-600 underline-offset-4 hover:underline"
|
||||||
>
|
>
|
||||||
去输入激活码
|
去输入激活码
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { revalidatePath } from "next/cache";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { db } from "@/db";
|
import { db } from "@/db";
|
||||||
import { activationCodes, sessions, taskInstances, taskTemplates, users } from "@/db/schema";
|
import { activationCodes, sessions, taskInstances, taskTemplates, users } from "@/db/schema";
|
||||||
|
import { SUBJECT_VALUES } from "@/db/schema";
|
||||||
import { todayStr } from "@/lib/dates";
|
import { todayStr } from "@/lib/dates";
|
||||||
import { getSessionUser } from "@/lib/auth";
|
import { getSessionUser } from "@/lib/auth";
|
||||||
|
|
||||||
@@ -76,6 +77,7 @@ export async function makeupTask(instanceId: number, done: boolean) {
|
|||||||
const templateSchema = z.object({
|
const templateSchema = z.object({
|
||||||
childId: z.coerce.number().int().positive(),
|
childId: z.coerce.number().int().positive(),
|
||||||
dow: z.coerce.number().int().min(0).max(6),
|
dow: z.coerce.number().int().min(0).max(6),
|
||||||
|
subject: z.enum(SUBJECT_VALUES).catch("other"),
|
||||||
title: z.string().trim().min(1, "任务内容不能为空").max(100, "最多 100 字"),
|
title: z.string().trim().min(1, "任务内容不能为空").max(100, "最多 100 字"),
|
||||||
requiresPhoto: z.boolean(),
|
requiresPhoto: z.boolean(),
|
||||||
});
|
});
|
||||||
@@ -97,6 +99,7 @@ export async function addTemplate(formData: FormData) {
|
|||||||
const parsed = templateSchema.safeParse({
|
const parsed = templateSchema.safeParse({
|
||||||
childId: formData.get("childId"),
|
childId: formData.get("childId"),
|
||||||
dow: formData.get("dow"),
|
dow: formData.get("dow"),
|
||||||
|
subject: formData.get("subject"),
|
||||||
title: formData.get("title"),
|
title: formData.get("title"),
|
||||||
requiresPhoto: formData.get("requiresPhoto") === "on",
|
requiresPhoto: formData.get("requiresPhoto") === "on",
|
||||||
});
|
});
|
||||||
@@ -116,6 +119,7 @@ export async function addTemplate(formData: FormData) {
|
|||||||
await db.insert(taskTemplates).values({
|
await db.insert(taskTemplates).values({
|
||||||
childUserId: parsed.data.childId,
|
childUserId: parsed.data.childId,
|
||||||
dow: parsed.data.dow,
|
dow: parsed.data.dow,
|
||||||
|
subject: parsed.data.subject,
|
||||||
title: parsed.data.title,
|
title: parsed.data.title,
|
||||||
requiresPhoto: parsed.data.requiresPhoto,
|
requiresPhoto: parsed.data.requiresPhoto,
|
||||||
sortOrder: maxRow.maxSort + 1,
|
sortOrder: maxRow.maxSort + 1,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { logout } from "@/app/login/actions";
|
import { logout } from "@/app/login/actions";
|
||||||
|
import { BackgroundBlobs } from "@/components/background-blobs";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { DevicesTab } from "./devices-tab";
|
import { DevicesTab } from "./devices-tab";
|
||||||
@@ -13,10 +14,11 @@ export type OverviewData = {
|
|||||||
name: string;
|
name: string;
|
||||||
streak: number;
|
streak: number;
|
||||||
today: { done: number; total: number };
|
today: { done: number; total: number };
|
||||||
|
grammar: { done: number; total: number };
|
||||||
week: {
|
week: {
|
||||||
date: string;
|
date: string;
|
||||||
isToday: boolean;
|
isToday: boolean;
|
||||||
tasks: { id: number; title: string; status: "pending" | "done"; isMakeup: boolean }[];
|
tasks: { id: number; title: string; subject: string; status: "pending" | "done"; isMakeup: boolean }[];
|
||||||
}[];
|
}[];
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
@@ -25,7 +27,7 @@ export type TemplatesData = {
|
|||||||
kids: {
|
kids: {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
items: { id: number; dow: number; title: string; requiresPhoto: boolean }[];
|
items: { id: number; dow: number; title: string; subject: string; requiresPhoto: boolean }[];
|
||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -52,9 +54,12 @@ export function ParentDashboard({
|
|||||||
const kids = overview.kids.map((k) => ({ id: k.id, name: k.name }));
|
const kids = overview.kids.map((k) => ({ id: k.id, name: k.name }));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="mx-auto max-w-2xl space-y-5 p-4 pb-10">
|
<main className="relative mx-auto max-w-2xl space-y-5 p-4 pb-10">
|
||||||
|
<BackgroundBlobs />
|
||||||
<header className="flex items-center justify-between">
|
<header className="flex items-center justify-between">
|
||||||
<h1 className="text-2xl font-bold">家长端</h1>
|
<h1 className="text-2xl font-extrabold tracking-tight">
|
||||||
|
家长<span className="text-gradient">中心</span>
|
||||||
|
</h1>
|
||||||
<form action={logout}>
|
<form action={logout}>
|
||||||
<Button type="submit" variant="outline" size="sm">
|
<Button type="submit" variant="outline" size="sm">
|
||||||
退出登录
|
退出登录
|
||||||
@@ -63,10 +68,25 @@ export function ParentDashboard({
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<Tabs defaultValue="overview">
|
<Tabs defaultValue="overview">
|
||||||
<TabsList className="grid w-full grid-cols-3">
|
<TabsList className="grid w-full grid-cols-3 bg-slate-100/80">
|
||||||
<TabsTrigger value="overview">今日概览</TabsTrigger>
|
<TabsTrigger
|
||||||
<TabsTrigger value="templates">任务模板</TabsTrigger>
|
value="overview"
|
||||||
<TabsTrigger value="devices">设备管理</TabsTrigger>
|
className="data-[state=active]:bg-white data-[state=active]:text-indigo-600 data-[state=active]:shadow-soft"
|
||||||
|
>
|
||||||
|
今日概览
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger
|
||||||
|
value="templates"
|
||||||
|
className="data-[state=active]:bg-white data-[state=active]:text-indigo-600 data-[state=active]:shadow-soft"
|
||||||
|
>
|
||||||
|
任务模板
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger
|
||||||
|
value="devices"
|
||||||
|
className="data-[state=active]:bg-white data-[state=active]:text-indigo-600 data-[state=active]:shadow-soft"
|
||||||
|
>
|
||||||
|
设备管理
|
||||||
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<TabsContent value="overview" className="mt-4">
|
<TabsContent value="overview" className="mt-4">
|
||||||
<OverviewTab data={overview} />
|
<OverviewTab data={overview} />
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { Flame } from "lucide-react";
|
|||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { subjectMeta } from "@/lib/subjects";
|
||||||
import { makeupTask } from "./actions";
|
import { makeupTask } from "./actions";
|
||||||
import type { OverviewData } from "./dashboard";
|
import type { OverviewData } from "./dashboard";
|
||||||
|
|
||||||
@@ -35,6 +37,20 @@ export function OverviewTab({ data }: { data: OverviewData }) {
|
|||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
今日完成 {kid.today.done} / {kid.today.total} 项
|
今日完成 {kid.today.done} / {kid.today.total} 项
|
||||||
</p>
|
</p>
|
||||||
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
|
<span className="shrink-0">英语语法</span>
|
||||||
|
<div className="h-1.5 flex-1 overflow-hidden rounded-full bg-slate-100">
|
||||||
|
<div
|
||||||
|
className="h-full rounded-full bg-gradient-to-r from-indigo-500 to-violet-500"
|
||||||
|
style={{
|
||||||
|
width: `${kid.grammar.total ? (kid.grammar.done / kid.grammar.total) * 100 : 0}%`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<span className="shrink-0 font-medium text-indigo-600">
|
||||||
|
{kid.grammar.done}/{kid.grammar.total}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{kid.week.map((day) => (
|
{kid.week.map((day) => (
|
||||||
<div key={day.date} className="rounded-lg border p-2">
|
<div key={day.date} className="rounded-lg border p-2">
|
||||||
@@ -49,6 +65,7 @@ export function OverviewTab({ data }: { data: OverviewData }) {
|
|||||||
{day.tasks.map((t) => (
|
{day.tasks.map((t) => (
|
||||||
<span key={t.id} className="inline-flex items-center gap-1">
|
<span key={t.id} className="inline-flex items-center gap-1">
|
||||||
<Badge variant={t.status === "done" ? "default" : "secondary"}>
|
<Badge variant={t.status === "done" ? "default" : "secondary"}>
|
||||||
|
<span className={cn("size-1.5 rounded-full", subjectMeta(t.subject).dot)} />
|
||||||
{t.title}
|
{t.title}
|
||||||
{t.isMakeup && " · 补"}
|
{t.isMakeup && " · 补"}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { SESSION_COOKIE, getSessionUser } from "@/lib/auth";
|
|||||||
import { daysAgo, todayStr } from "@/lib/dates";
|
import { daysAgo, todayStr } from "@/lib/dates";
|
||||||
import { ensureDay } from "@/lib/tasks";
|
import { ensureDay } from "@/lib/tasks";
|
||||||
import { streakOf } from "@/lib/streak";
|
import { streakOf } from "@/lib/streak";
|
||||||
|
import { passedSet } from "@/lib/grammar";
|
||||||
|
import { TOTAL } from "@/content/grammar";
|
||||||
import { ParentDashboard, type DevicesData, type OverviewData, type TemplatesData } from "./dashboard";
|
import { ParentDashboard, type DevicesData, type OverviewData, type TemplatesData } from "./dashboard";
|
||||||
|
|
||||||
const SHANGHAI = { timeZone: "Asia/Shanghai" } as const;
|
const SHANGHAI = { timeZone: "Asia/Shanghai" } as const;
|
||||||
@@ -32,13 +34,15 @@ export default async function ParentPage() {
|
|||||||
const overview: OverviewData = { kids: [] };
|
const overview: OverviewData = { kids: [] };
|
||||||
for (const kid of kids) {
|
for (const kid of kids) {
|
||||||
await ensureDay(kid.id, today); // 家长先看时也要生成今天的快照
|
await ensureDay(kid.id, today); // 家长先看时也要生成今天的快照
|
||||||
const [streak, rows] = await Promise.all([
|
const [streak, gDone, rows] = await Promise.all([
|
||||||
streakOf(kid.id),
|
streakOf(kid.id),
|
||||||
|
passedSet(kid.id).then((s) => s.size),
|
||||||
db
|
db
|
||||||
.select({
|
.select({
|
||||||
id: taskInstances.id,
|
id: taskInstances.id,
|
||||||
date: taskInstances.date,
|
date: taskInstances.date,
|
||||||
title: taskInstances.title,
|
title: taskInstances.title,
|
||||||
|
subject: taskInstances.subject,
|
||||||
status: taskInstances.status,
|
status: taskInstances.status,
|
||||||
isMakeup: taskInstances.isMakeup,
|
isMakeup: taskInstances.isMakeup,
|
||||||
sortOrder: taskInstances.sortOrder,
|
sortOrder: taskInstances.sortOrder,
|
||||||
@@ -63,6 +67,7 @@ export default async function ParentPage() {
|
|||||||
total: todayTasks.length,
|
total: todayTasks.length,
|
||||||
done: todayTasks.filter((t) => t.status === "done").length,
|
done: todayTasks.filter((t) => t.status === "done").length,
|
||||||
},
|
},
|
||||||
|
grammar: { done: gDone, total: TOTAL },
|
||||||
week,
|
week,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -85,6 +90,7 @@ export default async function ParentPage() {
|
|||||||
id: t.id,
|
id: t.id,
|
||||||
dow: t.dow,
|
dow: t.dow,
|
||||||
title: t.title,
|
title: t.title,
|
||||||
|
subject: t.subject,
|
||||||
requiresPhoto: t.requiresPhoto,
|
requiresPhoto: t.requiresPhoto,
|
||||||
})),
|
})),
|
||||||
})),
|
})),
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { SUBJECTS, type Subject, subjectMeta } from "@/lib/subjects";
|
||||||
import { addTemplate, deleteTemplate } from "./actions";
|
import { addTemplate, deleteTemplate } from "./actions";
|
||||||
import type { TemplatesData } from "./dashboard";
|
import type { TemplatesData } from "./dashboard";
|
||||||
|
|
||||||
@@ -32,6 +34,7 @@ function KidTemplateCard({
|
|||||||
kid: TemplatesData["kids"][number];
|
kid: TemplatesData["kids"][number];
|
||||||
}) {
|
}) {
|
||||||
const [dow, setDow] = useState(1);
|
const [dow, setDow] = useState(1);
|
||||||
|
const [subject, setSubject] = useState<Subject>("other");
|
||||||
const [title, setTitle] = useState("");
|
const [title, setTitle] = useState("");
|
||||||
const [requiresPhoto, setRequiresPhoto] = useState(false);
|
const [requiresPhoto, setRequiresPhoto] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
@@ -43,6 +46,7 @@ function KidTemplateCard({
|
|||||||
const fd = new FormData();
|
const fd = new FormData();
|
||||||
fd.set("childId", String(kid.id));
|
fd.set("childId", String(kid.id));
|
||||||
fd.set("dow", String(dow));
|
fd.set("dow", String(dow));
|
||||||
|
fd.set("subject", subject);
|
||||||
fd.set("title", title);
|
fd.set("title", title);
|
||||||
if (requiresPhoto) fd.set("requiresPhoto", "on");
|
if (requiresPhoto) fd.set("requiresPhoto", "on");
|
||||||
startTransition(async () => {
|
startTransition(async () => {
|
||||||
@@ -74,23 +78,32 @@ function KidTemplateCard({
|
|||||||
{items.length === 0 && (
|
{items.length === 0 && (
|
||||||
<span className="text-sm text-muted-foreground">休息日(自动保持连击)</span>
|
<span className="text-sm text-muted-foreground">休息日(自动保持连击)</span>
|
||||||
)}
|
)}
|
||||||
{items.map((item) => (
|
{items.map((item) => {
|
||||||
<span
|
const sm = subjectMeta(item.subject);
|
||||||
key={item.id}
|
return (
|
||||||
className="inline-flex items-center gap-1 rounded-full bg-muted px-3 py-1 text-sm"
|
<span
|
||||||
>
|
key={item.id}
|
||||||
{item.title}
|
className={cn(
|
||||||
{item.requiresPhoto && " · 拍照"}
|
"inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-sm ring-1",
|
||||||
<button
|
sm.soft,
|
||||||
type="button"
|
sm.ring,
|
||||||
aria-label={`删除 ${item.title}`}
|
)}
|
||||||
className="ml-1 text-muted-foreground hover:text-destructive"
|
|
||||||
onClick={() => startTransition(() => deleteTemplate(item.id))}
|
|
||||||
>
|
>
|
||||||
<Trash2 className="size-3.5" />
|
<span className={cn("size-1.5 rounded-full", sm.dot)} />
|
||||||
</button>
|
<span className="font-medium">{sm.label}</span>
|
||||||
</span>
|
<span className="text-slate-600">{item.title}</span>
|
||||||
))}
|
{item.requiresPhoto && <span className="text-muted-foreground">· 拍照</span>}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={`删除 ${item.title}`}
|
||||||
|
className="ml-1 text-muted-foreground hover:text-destructive"
|
||||||
|
onClick={() => startTransition(() => deleteTemplate(item.id))}
|
||||||
|
>
|
||||||
|
<Trash2 className="size-3.5" />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -98,6 +111,20 @@ function KidTemplateCard({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form onSubmit={onAdd} className="flex flex-wrap items-end gap-3 border-t pt-3">
|
<form onSubmit={onAdd} className="flex flex-wrap items-end gap-3 border-t pt-3">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<Label>科目</Label>
|
||||||
|
<select
|
||||||
|
value={subject}
|
||||||
|
onChange={(e) => setSubject(e.target.value as Subject)}
|
||||||
|
className="h-9 rounded-md border border-input bg-background px-2 text-sm"
|
||||||
|
>
|
||||||
|
{SUBJECTS.map((s) => (
|
||||||
|
<option key={s.key} value={s.key}>
|
||||||
|
{s.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Label>星期</Label>
|
<Label>星期</Label>
|
||||||
<select
|
<select
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// 页面氛围光斑:两个大号模糊渐变圆,固定于背景(企业信任风的纵深元素)
|
||||||
|
export function BackgroundBlobs() {
|
||||||
|
return (
|
||||||
|
<div aria-hidden className="pointer-events-none fixed inset-0 -z-10 overflow-hidden">
|
||||||
|
<div className="bg-blob -top-32 -right-24 size-[480px] bg-indigo-300/30" />
|
||||||
|
<div className="bg-blob -bottom-40 -left-24 size-[420px] bg-violet-300/25" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,17 +5,19 @@ import { Slot } from "radix-ui"
|
|||||||
import { cn } from "@/lib/utils"
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"inline-flex shrink-0 items-center justify-center gap-2 rounded-lg text-sm font-semibold whitespace-nowrap transition-all duration-200 outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
// 主按钮:靛蓝→紫罗兰渐变 + 带色阴影 + 悬浮抬升
|
||||||
|
default:
|
||||||
|
"bg-gradient-to-r from-indigo-600 to-violet-600 text-white shadow-btn hover:-translate-y-0.5 hover:shadow-lift",
|
||||||
destructive:
|
destructive:
|
||||||
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
|
||||||
outline:
|
outline:
|
||||||
"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
"border border-slate-200 bg-white text-slate-700 shadow-xs hover:-translate-y-0.5 hover:border-slate-300 hover:bg-slate-50",
|
||||||
secondary:
|
secondary:
|
||||||
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
"border border-slate-200 bg-white text-slate-700 hover:border-slate-300 hover:bg-slate-50",
|
||||||
ghost:
|
ghost:
|
||||||
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
||||||
link: "text-primary underline-offset-4 hover:underline",
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
<div
|
<div
|
||||||
data-slot="card"
|
data-slot="card"
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col gap-6 rounded-xl border bg-card py-6 text-card-foreground shadow-sm",
|
"flex flex-col gap-6 rounded-xl border border-slate-100 bg-card py-6 text-card-foreground shadow-soft transition-shadow duration-200 hover:shadow-lift",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import { week01 } from "./week01";
|
||||||
|
import { week02 } from "./week02";
|
||||||
|
import { week03 } from "./week03";
|
||||||
|
import { week04 } from "./week04";
|
||||||
|
import { week05 } from "./week05";
|
||||||
|
import { week06 } from "./week06";
|
||||||
|
import { week07 } from "./week07";
|
||||||
|
import { week08 } from "./week08";
|
||||||
|
import { week09 } from "./week09";
|
||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 月测 1:覆盖第 1–4 周(A1–A2 时态、名词、介词、情态、比较级)
|
||||||
|
const month01: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "monthly",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "第 1 个月测验",
|
||||||
|
intro: "综合第 1–4 周:be 动词、现在时、过去时、冠词、代词、介词、can、比较级。共 12 题,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "There ___ two apples on the table.", options: ["is", "are", "am"], answer: 1, explain: "two apples 复数 → are。" },
|
||||||
|
{ q: "She ___ to school by bike every day.", options: ["go", "goes", "going"], answer: 1, explain: "she 单三 → goes。" },
|
||||||
|
{ q: "Look! The baby ___ .", options: ["sleeps", "is sleeping", "sleep"], answer: 1, explain: "Look 提示此刻 → 现在进行时。" },
|
||||||
|
{ q: "I ___ a movie last night.", options: ["watch", "watched", "watching"], answer: 1, explain: "last night → 过去时 watched。" },
|
||||||
|
{ q: "He ___ play the guitar when he was five.", options: ["can", "could", "cans"], answer: 1, explain: "过去的能力 → could。" },
|
||||||
|
{ q: "This book is ___ than that one.", options: ["interesting", "more interesting", "most interesting"], answer: 1, explain: "两者比较用比较级 more interesting。" },
|
||||||
|
{ q: "We met ___ Monday ___ the morning.", options: ["on / in", "in / on", "at / in"], answer: 0, explain: "星期用 on,上午用 in the morning。" },
|
||||||
|
{ q: "Is there ___ milk in the fridge?", options: ["some", "any", "a"], answer: 1, explain: "疑问句用 any。" },
|
||||||
|
{ q: "The cat is sleeping ___ the sofa.", options: ["on", "in", "at"], answer: 0, explain: "在沙发表面 → on。" },
|
||||||
|
{ q: "___ you like some tea? — Yes, please.", options: ["Do", "Would", "Are"], answer: 1, explain: "礼貌提供用 Would you like。" },
|
||||||
|
{ q: "My sister ___ got long hair.", options: ["have", "has", "is"], answer: 1, explain: "she → has got。" },
|
||||||
|
{ q: "They didn’t ___ the bus.", options: ["catch", "caught", "catched"], answer: 0, explain: "didn’t 后用原形 catch。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 月测 2:覆盖第 5–8 周(将来时、完成时、条件句、被动、间接引语、定语从句)
|
||||||
|
const month02: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "monthly",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "第 2 个月测验",
|
||||||
|
intro: "综合第 5–8 周:将来时、现在完成时、条件句、wish、被动语态、间接引语、定语从句。共 12 题,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "I think it ___ tomorrow.", options: ["rains", "will rain", "rained"], answer: 1, explain: "预测用 will。" },
|
||||||
|
{ q: "She ___ just ___ her homework.", options: ["has / finished", "have / finish", "had / finishes"], answer: 0, explain: "she + has just + 过去分词。" },
|
||||||
|
{ q: "I ___ here since 2020.", options: ["live", "lived", "have lived"], answer: 2, explain: "since + 现在完成时。" },
|
||||||
|
{ q: "If it rains, we ___ at home.", options: ["stay", "will stay", "stayed"], answer: 1, explain: "第一条件句:if 现在时,主句 will。" },
|
||||||
|
{ q: "If I ___ rich, I would travel the world.", options: ["am", "were", "will be"], answer: 1, explain: "第二条件句用 were。" },
|
||||||
|
{ q: "I wish I ___ taller.", options: ["am", "was/were", "will be"], answer: 1, explain: "wish 现在遗憾用过去式。" },
|
||||||
|
{ q: "The letter ___ yesterday.", options: ["sent", "was sent", "is sent"], answer: 1, explain: "昨天 + 被动 → was sent。" },
|
||||||
|
{ q: "He said that he ___ tired.", options: ["is", "was", "be"], answer: 1, explain: "间接引语时态后移 is→was。" },
|
||||||
|
{ q: "The boy ___ won the race is my cousin.", options: ["which", "who", "whom"], answer: 1, explain: "指人作主语用 who。" },
|
||||||
|
{ q: "You ___ be joking! That’s impossible.", options: ["must", "can’t", "should"], answer: 1, explain: "强烈否定推测用 can’t。" },
|
||||||
|
{ q: "It’s cold, ___ ?", options: ["is it", "isn’t it", "doesn’t it"], answer: 1, explain: "前肯后否反意疑问。" },
|
||||||
|
{ q: "She decided ___ a new job.", options: ["find", "to find", "finding"], answer: 1, explain: "decide + to do。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 课程注册表:按线性顺序拼接,seq 从 1 起;月测插在每 4 周之后
|
||||||
|
// 后续周次以同样方式追加到 WEEKS 数组即可,其余逻辑自动适配
|
||||||
|
const WEEKS: SyllabusEntry[][] = [
|
||||||
|
week01,
|
||||||
|
week02,
|
||||||
|
week03,
|
||||||
|
week04,
|
||||||
|
month01,
|
||||||
|
week05,
|
||||||
|
week06,
|
||||||
|
week07,
|
||||||
|
week08,
|
||||||
|
month02,
|
||||||
|
week09,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const SYLLABUS = WEEKS.flat().map((entry, i) => ({ ...entry, seq: i + 1 }));
|
||||||
|
export const TOTAL = SYLLABUS.length;
|
||||||
|
|
||||||
|
export type Entry = (typeof SYLLABUS)[number];
|
||||||
|
|
||||||
|
export function entryBySeq(seq: number): Entry | undefined {
|
||||||
|
return SYLLABUS.find((e) => e.seq === seq);
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
// 英语语法课程内容的类型定义
|
||||||
|
// 说明:课程正文、例句、练习、测验题均为原创,仅参考两份语法书的"主题目录"做编排,
|
||||||
|
// 不复制其正文文字、图表或习题。
|
||||||
|
|
||||||
|
export type Cefr = "A1" | "A2" | "B1" | "B2" | "C1";
|
||||||
|
|
||||||
|
// 一道题(单选):options 为选项列表,answer 为正确项下标,explain 为解析
|
||||||
|
export type QuizQ = {
|
||||||
|
q: string;
|
||||||
|
options: string[];
|
||||||
|
answer: number;
|
||||||
|
explain: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 一个"结构图":用简单表格直观呈现语法结构(代替插图)
|
||||||
|
export type Structure = { cols: string[]; rows: string[][] };
|
||||||
|
|
||||||
|
// 课程中的一个讲解小节
|
||||||
|
export type Section = {
|
||||||
|
heading: string; // 英文小标题
|
||||||
|
zh: string; // 一句话中文要点,帮助初学者理解
|
||||||
|
body: string; // 原创讲解(英文为主)
|
||||||
|
examples?: string[]; // 原创例句
|
||||||
|
structure?: Structure; // 结构表
|
||||||
|
note?: string; // 易错点 / 小贴士
|
||||||
|
};
|
||||||
|
|
||||||
|
// 一节课(约 60 分钟学习量)
|
||||||
|
export type Lesson = {
|
||||||
|
type: "lesson";
|
||||||
|
cefr: Cefr;
|
||||||
|
title: string; // 语法主题
|
||||||
|
goal: string; // 一句话学习目标
|
||||||
|
sections: Section[];
|
||||||
|
practice: QuizQ[]; // 课内随练,做完即显示答案,不计分
|
||||||
|
quiz: QuizQ[]; // 课后测验,计分,≥80% 通过
|
||||||
|
};
|
||||||
|
|
||||||
|
// 周测 / 月测里程碑(只有测验,无讲解)
|
||||||
|
export type Milestone = {
|
||||||
|
type: "weekly" | "monthly";
|
||||||
|
cefr: Cefr;
|
||||||
|
title: string;
|
||||||
|
intro: string;
|
||||||
|
quiz: QuizQ[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SyllabusEntry = Lesson | Milestone;
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 第 1 周:A1 起步 —— 动词 be、一般现在时、否定与疑问、冠词与复数、指示词与物主、代词与语序
|
||||||
|
// 全部讲解、例句、练习、测验均为原创。
|
||||||
|
|
||||||
|
export const week01: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "The verb “be” (am / is / are)",
|
||||||
|
goal: "学会用 am / is / are 描述身份、状态和地点。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Three forms of “be”",
|
||||||
|
zh: "be 动词随主语变:我用 am,你用 are,is 跟着他/她/它。",
|
||||||
|
body: "The verb “be” is the most common verb in English. In the present tense it has three forms: “am”, “is”, and “are”. We choose the form by looking at the subject (the person or thing we talk about). “I” always goes with “am”. “He”, “she”, “it”, and any single name go with “is”. “You”, “we”, “they”, and plural nouns go with “are”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Subject", "be", "Example"],
|
||||||
|
rows: [
|
||||||
|
["I", "am", "I am a student."],
|
||||||
|
["He / She / It", "is", "She is happy."],
|
||||||
|
["You / We / They", "are", "They are at home."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I am ten years old.", "My brother is tall.", "We are friends."],
|
||||||
|
note: "“You” always takes “are”, even when “you” means just one person.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Short forms (contractions)",
|
||||||
|
zh: "口语和写作里常把主语和 be 缩在一起。",
|
||||||
|
body: "In speaking and in informal writing we usually shorten the subject and “be” together. “I am” becomes “I’m”, “she is” becomes “she’s”, “they are” becomes “they’re”. The meaning stays exactly the same.",
|
||||||
|
examples: ["I’m tired.", "He’s a doctor.", "We’re ready.", "You’re kind."],
|
||||||
|
note: "We do not contract “am not” into “I amn’t”. The negative short form is “I’m not”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "What we use “be” for",
|
||||||
|
zh: "be 用来表达身份、感觉、年龄、地点。",
|
||||||
|
body: "We use “be” to say who someone is, how someone feels, how old someone is, and where someone is. English does not use a separate verb for age the way some languages do — we say “I am ten”, not “I have ten”.",
|
||||||
|
examples: ["She is my teacher.", "I am hungry.", "He is twelve.", "The book is on the desk."],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I ___ a pupil.", options: ["am", "is", "are"], answer: 0, explain: "主语是 I,用 am。" },
|
||||||
|
{ q: "The cats ___ in the garden.", options: ["am", "is", "are"], answer: 2, explain: "cats 是复数,用 are。" },
|
||||||
|
{ q: "Tom ___ my friend.", options: ["am", "is", "are"], answer: 1, explain: "Tom 是单数人名,用 is。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "She ___ very clever.", options: ["am", "is", "are"], answer: 1, explain: "She → is。" },
|
||||||
|
{ q: "You ___ late today.", options: ["am", "is", "are"], answer: 2, explain: "You → are。" },
|
||||||
|
{ q: "My parents ___ at work.", options: ["is", "are", "am"], answer: 1, explain: "parents 复数 → are。" },
|
||||||
|
{ q: "I ___ eleven years old.", options: ["have", "am", "is"], answer: 1, explain: "说年龄用 be:I am。" },
|
||||||
|
{ q: "It ___ a sunny day.", options: ["are", "is", "am"], answer: 1, explain: "It → is。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "The present simple (positive)",
|
||||||
|
goal: "学会用一般现在时陈述习惯与事实,掌握第三人称单数加 -s。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "What the present simple means",
|
||||||
|
zh: "一般现在时表示经常发生的事或不变的事实。",
|
||||||
|
body: "We use the present simple for things that happen again and again (habits and routines), and for facts that are always true. Examples of habits: “I walk to school.” Facts: “The sun rises in the east.”",
|
||||||
|
examples: ["I get up at seven.", "Birds fly.", "My father works in a bank."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The -s ending",
|
||||||
|
zh: "I/you/we/they 用原形;he/she/it 在动词后加 -s 或 -es。",
|
||||||
|
body: "For “I”, “you”, “we”, “they” the verb stays in its base form. But for “he”, “she”, “it”, and any single name, we add “-s” to the verb. This is the one rule that learners forget most often, so remember it well.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Subject", "Verb form", "Example"],
|
||||||
|
rows: [
|
||||||
|
["I / You / We / They", "base form", "We play football."],
|
||||||
|
["He / She / It / a name", "base + -s", "He plays football."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I like apples.", "She likes apples.", "They read every night.", "Tom reads every night."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Spelling rules for -s and -es",
|
||||||
|
zh: "以 -sh/-ch/-s/-x/-o 结尾的动词加 -es;辅音+y 结尾变 y 为 i 再加 -es。",
|
||||||
|
body: "Most verbs just add “-s”. Verbs ending in -sh, -ch, -ss, -x, or -o add “-es” so we can pronounce them: “watch → watches”, “go → goes”. Verbs ending in a consonant + y change the y to i and add “-es”: “study → studies”. A vowel before y just adds “-s”: “play → plays”.",
|
||||||
|
examples: ["wash → washes", "watch → watches", "study → studies", "play → plays"],
|
||||||
|
note: "“has” is the only irregular form here: have → has for he/she/it.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "He ___ (play) the piano.", options: ["play", "plays", "playes"], answer: 1, explain: "he 加 -s:plays。" },
|
||||||
|
{ q: "They ___ (go) home by bus.", options: ["go", "goes", "gos"], answer: 0, explain: "they 用原形 go。" },
|
||||||
|
{ q: "She ___ (study) English.", options: ["studys", "studies", "study"], answer: 1, explain: "辅音+y → i+es:studies。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "My sister ___ milk every morning.", options: ["drink", "drinks", "drinking"], answer: 1, explain: "sister 单数 → drinks。" },
|
||||||
|
{ q: "We ___ in a small town.", options: ["live", "lives", "lived"], answer: 0, explain: "we 用原形 live。" },
|
||||||
|
{ q: "The bus ___ at eight.", options: ["leave", "leaves", "leavs"], answer: 1, explain: "bus 单数 → leaves。" },
|
||||||
|
{ q: "I ___ my teeth twice a day.", options: ["brush", "brushs", "brushes"], answer: 0, explain: "I 用原形 brush。" },
|
||||||
|
{ q: "Anna ___ a red bike.", options: ["have", "has", "haves"], answer: 1, explain: "单数第三人称 have→has。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "Present simple: negatives and questions",
|
||||||
|
goal: "用 do / does 造否定句和疑问句。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Negatives with don’t / doesn’t",
|
||||||
|
zh: "否定句用 don't(I/you/we/they)或 doesn't(he/she/it),动词回到原形。",
|
||||||
|
body: "To make a negative sentence in the present simple, we use the helper “do not” (don’t) or “does not” (doesn’t) before the base form of the verb. Notice that after “doesn’t” the main verb loses its -s and returns to the base form.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Subject", "helper", "verb", "Example"],
|
||||||
|
rows: [
|
||||||
|
["I / You / We / They", "don’t", "base", "I don’t like fish."],
|
||||||
|
["He / She / It", "doesn’t", "base", "He doesn’t like fish."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["We don’t have a car.", "She doesn’t eat meat.", "It doesn’t rain much here."],
|
||||||
|
note: "Say “he doesn’t like”, never “he doesn’t likes”. The -s is already inside “doesn’t”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Yes/No questions with Do / Does",
|
||||||
|
zh: "一般疑问句把 Do/Does 放句首,回答用短答语。",
|
||||||
|
body: "For yes/no questions we put “Do” or “Does” at the front, then the subject, then the base verb. Short answers repeat the helper: “Yes, I do.” / “No, she doesn’t.”",
|
||||||
|
examples: ["Do you like music? — Yes, I do.", "Does he play tennis? — No, he doesn’t."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Wh- questions",
|
||||||
|
zh: "特殊疑问句在 Do/Does 前加疑问词(what/where/when/why/who)。",
|
||||||
|
body: "To ask for information we add a question word before “do/does”. “What do you eat?” “Where does she live?” “Who” is special: when “who” is the subject, the verb takes -s and we do not use “do/does”: “Who lives here?”",
|
||||||
|
examples: ["What time do you get up?", "Where do they study?", "Who wants tea?"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She ___ like coffee.", options: ["don’t", "doesn’t", "not"], answer: 1, explain: "she → doesn’t。" },
|
||||||
|
{ q: "___ you speak French?", options: ["Do", "Does", "Are"], answer: 0, explain: "you → Do。" },
|
||||||
|
{ q: "Where ___ he work?", options: ["do", "does", "is"], answer: 1, explain: "he → does。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "They ___ not want to go.", options: ["do", "does", "is"], answer: 0, explain: "they → do。" },
|
||||||
|
{ q: "Does your dog ___ fast?", options: ["runs", "run", "running"], answer: 1, explain: "Does 后用原形 run。" },
|
||||||
|
{ q: "I ___ not understand.", options: ["does", "do", "am"], answer: 1, explain: "I → do。" },
|
||||||
|
{ q: "___ it snow here in winter?", options: ["Do", "Does", "Is"], answer: 1, explain: "it → Does。" },
|
||||||
|
{ q: "Who ___ in this house?", options: ["live", "lives", "do live"], answer: 1, explain: "who 作主语,动词加 -s:lives。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "a / an / the and plural nouns",
|
||||||
|
goal: "区分不定冠词 a/an、定冠词 the,以及名词单复数。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "a and an",
|
||||||
|
zh: "a 用于辅音音素开头,an 用于元音音素开头,指“一个”。",
|
||||||
|
body: "We use “a” or “an” with a singular countable noun when we mention it for the first time or mean “one of many”. The choice depends on the sound at the start, not the letter. Use “an” before a vowel sound (a, e, i, o, u sound) and “a” before a consonant sound.",
|
||||||
|
examples: ["a book", "an apple", "an hour (the h is silent)", "a university (starts with a 'y' sound)"],
|
||||||
|
note: "Watch “an hour” and “a university”: it is the sound that matters, not the spelling.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "the",
|
||||||
|
zh: "the 指双方都知道的、或唯一的那个事物。",
|
||||||
|
body: "We use “the” when the listener knows which thing we mean, or when there is only one. “Close the door” (the door of this room). “The sun” (there is only one sun for us).",
|
||||||
|
examples: ["Pass me the pen, please.", "The sky is blue.", "I read the book you gave me."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Plural nouns",
|
||||||
|
zh: "多数名词加 -s;以 -s/-sh/-ch/-x 加 -es;辅音+y 变 -ies。",
|
||||||
|
body: "Most nouns form the plural by adding “-s”. After -s, -sh, -ch, -x we add “-es”: “box → boxes”. A consonant + y changes to “-ies”: “city → cities”. Some common nouns are irregular and must be learned: “man → men”, “child → children”, “foot → feet”, “person → people”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Singular", "Plural"],
|
||||||
|
rows: [
|
||||||
|
["cat", "cats"],
|
||||||
|
["bus", "buses"],
|
||||||
|
["baby", "babies"],
|
||||||
|
["child", "children"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
note: "With a plural noun we usually do not use “a/an”: say “I like cats”, not “I like a cats”.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She is ___ honest girl.", options: ["a", "an", "the"], answer: 1, explain: "honest 的 h 不发音,元音音素开头 → an。" },
|
||||||
|
{ q: "Look at ___ moon!", options: ["a", "an", "the"], answer: 2, explain: "月亮独一无二 → the。" },
|
||||||
|
{ q: "two ___ (child)", options: ["childs", "children", "childes"], answer: 1, explain: "child 的复数是 children。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "He bought ___ umbrella.", options: ["a", "an", "the"], answer: 1, explain: "umbrella 元音开头 → an。" },
|
||||||
|
{ q: "___ water is cold today.", options: ["A", "An", "The"], answer: 2, explain: "特指今天的水 → The。" },
|
||||||
|
{ q: "I have three ___ .", options: ["box", "boxs", "boxes"], answer: 2, explain: "box 复数加 -es。" },
|
||||||
|
{ q: "She saw two ___ in the zoo.", options: ["mouses", "mice", "mices"], answer: 1, explain: "mouse 复数是 mice。" },
|
||||||
|
{ q: "It takes ___ hour.", options: ["a", "an", "—"], answer: 1, explain: "hour 的 h 不发音 → an。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "this / that / these / those and possessives",
|
||||||
|
goal: "用指示词指远近单复,用物主形容词表示“谁的”。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Near and far, one and many",
|
||||||
|
zh: "this/these 指近处,that/those 指远处;this/that 单数,these/those 复数。",
|
||||||
|
body: "“This” (near, one) and “that” (far, one) point at singular things. “These” (near, many) and “those” (far, many) point at plural things. “Near” means close to the speaker.",
|
||||||
|
structure: {
|
||||||
|
cols: ["", "near", "far"],
|
||||||
|
rows: [
|
||||||
|
["one", "this", "that"],
|
||||||
|
["many", "these", "those"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["This is my pen.", "That is a big tree.", "These are my shoes.", "Look at those birds."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Possessive adjectives",
|
||||||
|
zh: "my/your/his/her/its/our/their 放在名词前表示“谁的”。",
|
||||||
|
body: "Possessive adjectives come before a noun to show who something belongs to. Match them to the owner, not to the thing owned: “She loves her dog.” “He lost his keys.”",
|
||||||
|
structure: {
|
||||||
|
cols: ["owner", "possessive", "example"],
|
||||||
|
rows: [
|
||||||
|
["I", "my", "my bag"],
|
||||||
|
["you", "your", "your name"],
|
||||||
|
["he", "his", "his bike"],
|
||||||
|
["she", "her", "her cat"],
|
||||||
|
["we", "our", "our house"],
|
||||||
|
["they", "their", "their school"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
note: "Don’t confuse “its” (possession) with “it’s” (= it is). “The dog wagged its tail.”",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "___ (far, one) is my uncle.", options: ["This", "That", "These"], answer: 1, explain: "远+单数 → That。" },
|
||||||
|
{ q: "She did ___ homework.", options: ["his", "her", "its"], answer: 1, explain: "she → her。" },
|
||||||
|
{ q: "___ (near, many) are delicious.", options: ["That", "This", "These"], answer: 2, explain: "近+复数 → These。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "Tom forgot ___ book.", options: ["her", "his", "their"], answer: 1, explain: "Tom(he)→ his。" },
|
||||||
|
{ q: "Look at ___ clouds up there!", options: ["this", "that", "those"], answer: 2, explain: "远+复数 → those。" },
|
||||||
|
{ q: "We love ___ teacher.", options: ["our", "us", "we"], answer: 0, explain: "we → our。" },
|
||||||
|
{ q: "___ is a good idea.", options: ["These", "That", "Those"], answer: 1, explain: "单数想法 → That/This;这里指对方说的(较远)用 That。" },
|
||||||
|
{ q: "The cat cleaned ___ paws.", options: ["it’s", "its", "his"], answer: 1, explain: "表所属用 its(无撇号)。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "Subject & object pronouns, word order",
|
||||||
|
goal: "区分主格与宾格代词,掌握英语 S-V-O 语序。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Subject and object pronouns",
|
||||||
|
zh: "主格(I/he/she…)做主语,宾格(me/him/her…)做宾语。",
|
||||||
|
body: "Pronouns change form depending on their job. The subject form starts the sentence and does the action. The object form receives the action or follows a preposition. A common mistake is “Me and Tom went” — the subject form is “Tom and I went”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["subject", "object"],
|
||||||
|
rows: [
|
||||||
|
["I", "me"],
|
||||||
|
["he", "him"],
|
||||||
|
["she", "her"],
|
||||||
|
["we", "us"],
|
||||||
|
["they", "them"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["She calls me every day.", "I like them.", "Give it to us.", "He saw her at the park."],
|
||||||
|
note: "After a preposition (to, for, with, at) always use the object form: “with me”, not “with I”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "English word order: S – V – O",
|
||||||
|
zh: "英语基本语序是 主语-动词-宾语,时间和地点常放句尾。",
|
||||||
|
body: "A normal English sentence follows the order Subject – Verb – Object. Place and time information usually go at the end, and place normally comes before time: “I read a book (O) in bed (place) every night (time).”",
|
||||||
|
examples: ["She eats an apple.", "We play football after school.", "He sends me a message on Monday."],
|
||||||
|
note: "Unlike some languages, English cannot freely move the verb. Keep S-V-O and you will be understood.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "Please help ___ (I).", options: ["I", "me", "my"], answer: 1, explain: "动词后用宾格 me。" },
|
||||||
|
{ q: "___ (she) and I are cousins.", options: ["She", "Her", "Hers"], answer: 0, explain: "做主语用主格 She。" },
|
||||||
|
{ q: "They invited ___ (we).", options: ["we", "our", "us"], answer: 2, explain: "动词后用宾格 us。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "Tell ___ (he) the news.", options: ["he", "him", "his"], answer: 1, explain: "动词后宾格 him。" },
|
||||||
|
{ q: "Come with ___ (we)!", options: ["we", "us", "our"], answer: 1, explain: "介词 with 后宾格 us。" },
|
||||||
|
{ q: "___ (they) live near us.", options: ["They", "Them", "Their"], answer: 0, explain: "句首主语用 They。" },
|
||||||
|
{ q: "Choose the correct order:", options: ["every day / reads / she / a paper", "She reads a paper every day.", "Reads she a paper every day.", "She every day reads a paper."], answer: 1, explain: "标准 S-V-O + 时间置尾。" },
|
||||||
|
{ q: "My mother made ___ (we) a cake.", options: ["we", "us", "our"], answer: 1, explain: "间接宾语用宾格 us。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "weekly",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "第 1 周测验",
|
||||||
|
intro: "本周你学了 be 动词、一般现在时及其否定疑问、冠词与复数、指示词与物主、代词与语序。下面 10 题综合检测,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "There ___ a cat on the sofa.", options: ["am", "is", "are"], answer: 1, explain: "a cat 单数 → is。" },
|
||||||
|
{ q: "My brothers ___ football on Sundays.", options: ["play", "plays", "playing"], answer: 0, explain: "brothers 复数 → play。" },
|
||||||
|
{ q: "She ___ not drink milk.", options: ["do", "does", "is"], answer: 1, explain: "she → does。" },
|
||||||
|
{ q: "___ your father work here?", options: ["Do", "Does", "Is"], answer: 1, explain: "father 单数 → Does。" },
|
||||||
|
{ q: "He wants ___ orange.", options: ["a", "an", "the"], answer: 1, explain: "orange 元音开头 → an。" },
|
||||||
|
{ q: "I can see three ___ .", options: ["sheep", "sheeps", "sheepes"], answer: 0, explain: "sheep 单复同形。" },
|
||||||
|
{ q: "___ bag is this? — It’s ___ .", options: ["Who / my", "Whose / mine", "Whose / her"], answer: 1, explain: "Whose 问归属;答语用名词性物主 mine。" },
|
||||||
|
{ q: "Give the pen to ___ .", options: ["she", "her", "hers"], answer: 1, explain: "介词 to 后宾格 her。" },
|
||||||
|
{ q: "Pick the sentence with correct order:", options: ["football / play / we / Saturday / on", "We play football on Saturday.", "On Saturday play we football.", "We football play on Saturday."], answer: 1, explain: "S-V-O + 时间置尾。" },
|
||||||
|
{ q: "That ___ my grandparents.", options: ["is", "are", "am"], answer: 1, explain: "grandparents 复数 → are。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,440 @@
|
|||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 第 2 周:A1 进阶 —— there be、地点介词、时间介词、can、祈使句与 Let's、所有格
|
||||||
|
// 全部讲解、例句、练习、测验均为原创。
|
||||||
|
|
||||||
|
export const week02: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "There is / There are",
|
||||||
|
goal: "用 there is / there are 说明“某处存在某物”,会说肯定、否定与疑问。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Saying what exists",
|
||||||
|
zh: "想表达“有……存在”时,用 there is(单数)或 there are(复数)开头。",
|
||||||
|
body: "We use “there is” and “there are” to say that something exists in a place. The real subject comes after the verb, so the verb agrees with the noun that follows it. One thing takes “there is”; two or more things take “there are”. In speech we often shorten “there is” to “there’s”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Number", "Form", "Example"],
|
||||||
|
rows: [
|
||||||
|
["one", "there is (there’s)", "There is a lamp on my desk."],
|
||||||
|
["more than one", "there are", "There are five chairs in the room."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["There is a bird on the roof.", "There are many stars tonight."],
|
||||||
|
note: "With a list, the verb agrees with the first noun: “There is a pen and two books on the table.”",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Negative sentences",
|
||||||
|
zh: "否定用 there isn't / there aren't;也可用 no + 名词。",
|
||||||
|
body: "To say that something does not exist, put “not” after is/are: “there isn’t”, “there aren’t”. We often add “any” with plurals and with words we cannot count: “There aren’t any chairs.” “There isn’t any juice.” Another correct pattern is “there is no / there are no” plus the noun, which sounds a little stronger and is common on signs: “There is no parking here.”",
|
||||||
|
examples: [
|
||||||
|
"There isn’t a supermarket near my house.",
|
||||||
|
"There aren’t any eggs in the fridge.",
|
||||||
|
"There is no time to lose.",
|
||||||
|
],
|
||||||
|
note: "Do not say “there hasn’t a park”. Existence uses “be”, not “have”: “There isn’t a park here.”",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Questions and short answers",
|
||||||
|
zh: "疑问句把 is/are 提到 there 前;回答用 Yes, there is. / No, there aren't.",
|
||||||
|
body: "To ask whether something exists, we swap the order of the verb and “there”: “Is there…?” or “Are there…?” Short answers repeat the same verb: “Yes, there is.” / “No, there isn’t.” / “Yes, there are.” With plurals and uncountables we usually add “any” in the question, and question words go at the front: “How many shops are there in your street?”",
|
||||||
|
structure: {
|
||||||
|
cols: ["Question", "Yes", "No"],
|
||||||
|
rows: [
|
||||||
|
["Is there a bank near here?", "Yes, there is.", "No, there isn’t."],
|
||||||
|
["Are there any apples left?", "Yes, there are.", "No, there aren’t."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Is there a lift in your building?", "Are there any good films on tonight?"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "How much and how many with there is/are",
|
||||||
|
zh: "问数量:可数名词用 how many,不可数名词用 how much。",
|
||||||
|
body: "“There is/are” often appears with number questions. For things we can count one by one we ask “How many… are there?”. For things we measure rather than count, like water or money, we ask “How much… is there?”. The answer then uses “there is” or “there are” to match.",
|
||||||
|
examples: [
|
||||||
|
"How many players are there in a football team?",
|
||||||
|
"How much homework is there today?",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "There ___ a spider on the wall!", options: ["is", "are", "be"], answer: 0, explain: "a spider 单数 → is。" },
|
||||||
|
{ q: "There ___ ten apples in the box.", options: ["is", "are", "am"], answer: 1, explain: "ten apples 复数 → are。" },
|
||||||
|
{ q: "___ there any milk in the glass?", options: ["Is", "Are", "Do"], answer: 0, explain: "milk 不可数 → Is there。" },
|
||||||
|
{ q: "There ___ any buses at night here.", options: ["isn’t", "aren’t", "don’t"], answer: 1, explain: "buses 复数否定 → aren’t。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "There ___ some orange juice in the bottle.", options: ["is", "are", "have"], answer: 0, explain: "juice 不可数 → is。" },
|
||||||
|
{ q: "___ there a hospital in your town?", options: ["Are", "Is", "Do"], answer: 1, explain: "a hospital 单数 → Is there。" },
|
||||||
|
{ q: "There ___ two windows in my bedroom.", options: ["is", "are", "be"], answer: 1, explain: "two windows 复数 → are。" },
|
||||||
|
{ q: "There isn’t ___ bread on the table.", options: ["some", "any", "a"], answer: 1, explain: "否定句中用 any。" },
|
||||||
|
{ q: "How many desks ___ there in the classroom?", options: ["is", "are", "has"], answer: 1, explain: "desks 复数 → are there。" },
|
||||||
|
{ q: "“Are there any parks here?” — “No, ___ .”", options: ["there isn’t", "there aren’t", "they aren’t"], answer: 1, explain: "复数疑问的否定短答 → there aren’t。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "Prepositions of place: in, on, under, next to, between, in front of",
|
||||||
|
goal: "用常见地点介词准确描述物品的空间位置。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "in, on, under",
|
||||||
|
zh: "in 表示在里面,on 表示在表面上,under 表示在正下方。",
|
||||||
|
body: "Three little words describe very common positions. “In” means inside a space, container, or area: “in the box”, “in the garden”. “On” means touching the surface of something: “on the table”. “Under” means below something, often partly covered by it: “under the chair”. Together these three answer the question “Where is it?” for most everyday objects around the home and classroom.",
|
||||||
|
examples: [
|
||||||
|
"The toys are in the box.",
|
||||||
|
"My phone is on the kitchen table.",
|
||||||
|
"The cat is sleeping under the bed.",
|
||||||
|
],
|
||||||
|
note: "“On the wall” and “on the floor” also use “on”, because we think of walls and floors as surfaces.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "next to, between, in front of",
|
||||||
|
zh: "next to 在旁边,between 在两者之间,in front of 在……前面。",
|
||||||
|
body: "“Next to” (also “beside”) means right at the side of something, very close: “She sat next to me.” “Between” means in the middle of two things, or inside a group: “between the school and the shop”. “In front of” means ahead of something, on the side that faces you: “Don’t stand in front of me — I can’t see!” Its opposite is “behind”: “The bike is behind the door.”",
|
||||||
|
examples: [
|
||||||
|
"I sit next to Lily in class.",
|
||||||
|
"The bakery is between the bank and the post office.",
|
||||||
|
"Please don’t stand in front of the TV!",
|
||||||
|
],
|
||||||
|
note: "“In front of” (outside, ahead of) is not the same as “in the front of” (inside the front part): “The driver sits in the front of the bus.”",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Structure of a place sentence",
|
||||||
|
zh: "基本句型:某物 + be + 介词短语,介词短语也可放句首做强调。",
|
||||||
|
body: "A sentence about place usually follows “thing + be + preposition + the place”: “The cat is under the table.” The preposition is always followed by a noun or pronoun: “next to me”, not “next to I”. We can also start with the place phrase to point at it first, and then use “there is / there are” for what we find: “Under the tree there is a small dog.”",
|
||||||
|
structure: {
|
||||||
|
cols: ["Preposition", "Meaning", "Example"],
|
||||||
|
rows: [
|
||||||
|
["in", "inside", "The key is in my pocket."],
|
||||||
|
["on", "touching the surface", "The clock is on the wall."],
|
||||||
|
["under", "below", "Your shoes are under the chair."],
|
||||||
|
["next to", "at the side of", "The lamp is next to the sofa."],
|
||||||
|
["between", "in the middle of two", "I stand between Mum and Dad."],
|
||||||
|
["in front of", "ahead of", "There is a tree in front of our house."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Next to the school, there is a small park."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Asking and answering “Where…?”",
|
||||||
|
zh: "问位置用 Where is/are…? 回答用“介词短语”。",
|
||||||
|
body: "To ask about position we say “Where is…?” for one thing and “Where are…?” for several. The answer is often just a preposition phrase: “On the desk.” / “Behind the door.” / “Between the two books.” In full answers we keep the same be form as the question: “Where is the cat?” — “It is under the bed.” “Where are the keys?” — “They are in your bag.”",
|
||||||
|
examples: [
|
||||||
|
"Where are my glasses? — They are on your head!",
|
||||||
|
"Where is the station? — It is next to the library.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "The fish swims ___ the water.", options: ["on", "in", "under"], answer: 1, explain: "在水里(空间内部)→ in。" },
|
||||||
|
{ q: "Our school is ___ the hospital ___ the cinema.(两词)", options: ["next to; next to", "between; and", "in front of; and"], answer: 1, explain: "在两处之间 → between … and …。" },
|
||||||
|
{ q: "Don’t hide ___ the door; I can see you!", options: ["behind", "on", "between"], answer: 0, explain: "门后遮挡 → behind。" },
|
||||||
|
{ q: "The picture is ___ the wall.", options: ["under", "on", "in"], answer: 1, explain: "墙面是表面 → on。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "There is a lovely garden ___ our house.(屋外前方)", options: ["in front of", "in the front of", "between"], answer: 0, explain: "在房子外部的前面 → in front of。" },
|
||||||
|
{ q: "My pencil fell ___ the desk, so I can’t see it.", options: ["on", "under", "next to"], answer: 1, explain: "掉到桌子底下看不见 → under。" },
|
||||||
|
{ q: "The bank is ___ the bookshop and the café.", options: ["next to", "between", "in"], answer: 1, explain: "在两者之间 → between。" },
|
||||||
|
{ q: "The new bookshop is right ___ our school.", options: ["next to", "between", "in"], answer: 0, explain: "紧挨着 → next to,后直接接宾语,不加 and。" },
|
||||||
|
{ q: "“Where are the children?” — “They are ___ the garden.”", options: ["on", "in", "under"], answer: 1, explain: "花园是围合空间 → in the garden。" },
|
||||||
|
{ q: "The bus stop is right ___ our school gate.", options: ["in front of", "under", "between"], answer: 0, explain: "在校门正前方 → in front of。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "Prepositions of time: in, on, at",
|
||||||
|
goal: "用 at / on / in 正确搭配时刻、星期日期与年月季节。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "at for clock times and fixed points",
|
||||||
|
zh: "at 用于具体时刻和少数固定时间点(如 at night、at noon)。",
|
||||||
|
body: "We use “at” with clock times and with a few fixed points of the day: “at seven o’clock”, “at noon”, “at midnight”, “at night”. “At” is also used with festival periods when we mean the holiday time, such as “at Christmas”. Think of “at” as pointing at one small point on the time line.",
|
||||||
|
examples: [
|
||||||
|
"School starts at eight fifteen.",
|
||||||
|
"We often watch films at night.",
|
||||||
|
"The train leaves at half past six.",
|
||||||
|
],
|
||||||
|
note: "“At night” but “in the morning / in the afternoon / in the evening” — this is a fixed habit of English.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "on for days and dates",
|
||||||
|
zh: "on 用于星期、具体日期,以及带修饰的某一天。",
|
||||||
|
body: "We use “on” with days of the week, with full dates, and with particular days that carry a describing word: “on Monday”, “on 5th August”, “on my birthday”, “on a cold morning”, “on Christmas Day”. A useful test: if you can naturally add the word “day” to the expression, it almost certainly takes “on”. Notice that “on Monday morning” still keeps “on”, because the day word comes first.",
|
||||||
|
examples: [
|
||||||
|
"We have PE on Tuesdays and Fridays.",
|
||||||
|
"The party is on 1st June.",
|
||||||
|
"I saw her on a rainy afternoon.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "in for months, years, seasons and long periods",
|
||||||
|
zh: "in 用于月份、年份、季节、世纪和较长的时间段。",
|
||||||
|
body: "We use “in” with months, years, seasons, centuries, and with the main parts of the day: “in July”, “in 2026”, “in winter”, “in the 21st century”, “in the morning / afternoon / evening”. “In” also means “after a period of time from now”: “I will be back in ten minutes.” Think of “in” as the preposition for big blocks of time, while “at” marks small points and “on” marks days.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Preposition", "Used for", "Example"],
|
||||||
|
rows: [
|
||||||
|
["at", "clock time, point", "at nine o’clock / at night"],
|
||||||
|
["on", "days and dates", "on Sunday / on 2nd May"],
|
||||||
|
["in", "months, years, seasons, parts of day", "in March / in 2025 / in the evening"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["My grandmother was born in 1958.", "Flowers bloom in spring."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "No preposition with last / this / next / every",
|
||||||
|
zh: "last、this、next、every 等词前不加 in/on/at。",
|
||||||
|
body: "When a time word already carries “last”, “this”, “next”, “every”, or words like “tomorrow” and “yesterday”, we do not add another preposition. Say “I saw him last week”, not “on last week”; “See you tomorrow”, not “on tomorrow”. This is a very common mistake, because many other languages keep the preposition; in English these words already carry the time meaning, so “on” or “in” must be dropped.",
|
||||||
|
examples: [
|
||||||
|
"We will go camping next month.",
|
||||||
|
"She phones her grandpa every evening.",
|
||||||
|
"I finished the book yesterday.",
|
||||||
|
],
|
||||||
|
note: "Compare: “on Monday” but “this Monday” — drop the preposition once “this/next/last” appears.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I get up ___ seven o’clock.", options: ["in", "on", "at"], answer: 2, explain: "具体时刻 → at。" },
|
||||||
|
{ q: "Her birthday is ___ 3rd October.", options: ["in", "on", "at"], answer: 1, explain: "具体日期 → on。" },
|
||||||
|
{ q: "It often snows here ___ January.", options: ["at", "in", "on"], answer: 1, explain: "月份 → in。" },
|
||||||
|
{ q: "We visited the museum ___ Sunday.", options: ["on", "in", "at"], answer: 0, explain: "星期 → on。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "The library closes ___ half past eight ___ the evening.", options: ["at; in", "on; in", "at; on"], answer: 0, explain: "时刻用 at;the evening 用 in。" },
|
||||||
|
{ q: "Our sports day is ___ 15th September.", options: ["in", "at", "on"], answer: 2, explain: "具体日期 → on。" },
|
||||||
|
{ q: "I was born ___ 2012.", options: ["on", "in", "at"], answer: 1, explain: "年份 → in。" },
|
||||||
|
{ q: "Stars are beautiful ___ night.", options: ["in", "on", "at"], answer: 2, explain: "固定搭配 at night。" },
|
||||||
|
{ q: "___ summer we go to the seaside.", options: ["In", "On", "At"], answer: 0, explain: "季节 → in summer。" },
|
||||||
|
{ q: "He left home ___ last Friday.", options: ["on", "in", "—(不填)"], answer: 2, explain: "有 last 时不再加介词。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "can / can’t (ability and permission)",
|
||||||
|
goal: "用 can / can't 表达能力与许可,会造疑问句和短答。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Talking about ability",
|
||||||
|
zh: "can 表示“会、能够”,所有人称都用同一个 can。",
|
||||||
|
body: "We use “can” to say that someone has the ability to do something: “She can speak English.” “Can” is a modal verb, which means it never changes form: no -s, no -ing, and no “to” after it. The main verb always stays in its base form: “he can swim”, never “he cans” or “can to swim”. The negative is “can’t”; the full form “cannot” is written as one word.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Form", "Structure", "Example"],
|
||||||
|
rows: [
|
||||||
|
["positive", "subject + can + base verb", "She can play the violin."],
|
||||||
|
["negative", "subject + can’t + base verb", "I can’t ride a horse."],
|
||||||
|
["question", "Can + subject + base verb?", "Can you swim?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["My little brother can count to a hundred.", "Penguins can’t fly."],
|
||||||
|
note: "Never write “he cans” or “can to swim”. It is “he can swim”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Asking for and giving permission",
|
||||||
|
zh: "can 也用来请求或给予许可,语气比 may 更日常。",
|
||||||
|
body: "Besides ability, “can” is used to ask for permission and to give it. “Can I open the window?” is a normal, friendly way to ask. To agree we say “Yes, you can.”; to refuse, “No, you can’t.” “May” is a more formal alternative, but in everyday speech “can” is fine.",
|
||||||
|
examples: [
|
||||||
|
"Can I borrow your eraser?",
|
||||||
|
"You can sit here if you like.",
|
||||||
|
"Sorry, you can’t use my phone.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Questions and short answers",
|
||||||
|
zh: "疑问句把 can 提前;回答用 Yes, … can. / No, … can’t.",
|
||||||
|
body: "To make a question, put “can” before the subject: “Can they cook?” “Can she drive?” Short answers use “can” or “can’t” together with the matching pronoun: “Yes, she can.” / “No, they can’t.” In everyday talk we normally answer with this short form rather than repeating the whole sentence; saying the full sentence again (“Yes, she can cook.”) sounds emphatic or a little unnatural.",
|
||||||
|
examples: [
|
||||||
|
"Can your dad drive? — Yes, he can.",
|
||||||
|
"Can we go now? — No, you can’t. Dinner is almost ready.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "can vs be able to (a first look)",
|
||||||
|
zh: "be able to 与 can 意思相近,但能用于更多时态。",
|
||||||
|
body: "“Be able to” has a similar meaning to “can”: “She is able to run very fast.” At this level you can mostly use “can”. It is useful to know “be able to” because “can” has no future or perfect forms — later you will say “will be able to”. For now, “can” is the natural, everyday choice.",
|
||||||
|
examples: [
|
||||||
|
"He is able to speak three languages.",
|
||||||
|
"One day you will be able to drive.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She ___ play the guitar very well.", options: ["can", "cans", "can to"], answer: 0, explain: "情态动词 can 无 -s、不接 to。" },
|
||||||
|
{ q: "___ I go to the toilet, please?", options: ["Can", "Do", "Am"], answer: 0, explain: "请求许可用 Can I…?" },
|
||||||
|
{ q: "“Can he ski?” — “No, he ___ .”", options: ["doesn’t", "can’t", "isn’t"], answer: 1, explain: "can 提问,否定短答用 can’t。" },
|
||||||
|
{ q: "I ___ find my key anywhere!", options: ["can’t", "don’t can", "not can"], answer: 0, explain: "can 的否定直接加 not:can’t。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "___ you speak any other languages?", options: ["Do", "Can", "Are"], answer: 1, explain: "询问能力用 Can。" },
|
||||||
|
{ q: "My grandpa is 80, but he ___ still drive.", options: ["cans", "can", "can to"], answer: 1, explain: "can 无人称变化,后接原形。" },
|
||||||
|
{ q: "“Can we eat in the classroom?” — “No, you ___ .”", options: ["don’t", "aren’t", "can’t"], answer: 2, explain: "拒绝许可 → you can’t。" },
|
||||||
|
{ q: "Fish ___ live without water.", options: ["can’t", "don’t can", "can not to"], answer: 0, explain: "能力否定 → can’t + 原形。" },
|
||||||
|
{ q: "She ___ touch the ceiling; she is too short.", options: ["can’t", "isn’t able", "doesn’t can"], answer: 0, explain: "能力否定 → can’t + 原形 touch;isn’t able 后缺 to,doesn’t can 不是合法结构。" },
|
||||||
|
{ q: "___ your sister swim when she was five?", options: ["Can", "Could", "Do"], answer: 1, explain: "谈过去的能力用 could(can 的过去式)。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "Imperatives and Let’s",
|
||||||
|
goal: "用祈使句发出指令与请求,用 Let's 提出共同行动的建议。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "The imperative form",
|
||||||
|
zh: "祈使句直接用动词原形开头,主语 you 省略。",
|
||||||
|
body: "We use the imperative to tell people what to do — for instructions, orders, friendly advice, warnings, and offers. The sentence starts with the base form of the verb, and the subject “you” is understood but never written down. Conveniently, one single form works whether you are speaking to one person or to a whole crowd: “Sit down, Tom.” / “Sit down, everyone.”",
|
||||||
|
structure: {
|
||||||
|
cols: ["Use", "Example"],
|
||||||
|
rows: [
|
||||||
|
["instruction", "Turn left at the traffic lights."],
|
||||||
|
["order", "Stop talking!"],
|
||||||
|
["advice", "Take an umbrella; it looks rainy."],
|
||||||
|
["offer / invitation", "Have another biscuit."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Open your books at page twelve.", "Come in and sit down.", "Be careful with the hot soup."],
|
||||||
|
note: "The verb “be” keeps its full form in imperatives: “Be quiet!”, never “Are quiet!”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Negative imperatives",
|
||||||
|
zh: "否定祈使句在动词前加 Don't,意为“别……”。",
|
||||||
|
body: "To tell someone not to do something, put “Don’t” in front of the base verb. The rule is completely regular: “Don’t” + base verb, for every verb and every subject. With “be” we say “Don’t be”: “Don’t be shy.” / “Don’t be late.” Public signs love this form too: “Don’t feed the animals.” “Don’t walk on the grass.” Notice there is no subject and no “to” anywhere.",
|
||||||
|
examples: [
|
||||||
|
"Don’t run in the corridor.",
|
||||||
|
"Don’t forget your homework.",
|
||||||
|
"Don’t be sad — everything will be fine.",
|
||||||
|
],
|
||||||
|
note: "Do not say “Don’t to run” or “Not run”. It is always “Don’t + base verb”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Being polite: please",
|
||||||
|
zh: "加 please 让命令变成礼貌请求,可放句尾或句首。",
|
||||||
|
body: "A bare imperative can sound strong or even rude, so we add “please” to turn an order into a polite request. “Please” can go at the end, normally after a small pause in speech (“Open the window, please.”), or at the beginning for a little extra emphasis (“Please open the window.”). In writing, a comma usually separates it when it stands at the end. With family and close friends, “please” is often dropped and a friendly tone does the work.",
|
||||||
|
examples: [
|
||||||
|
"Pass me the salt, please.",
|
||||||
|
"Please close the window.",
|
||||||
|
"Wait for me here, please.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Let’s for suggestions",
|
||||||
|
zh: "Let's = let us,提议“咱们一起……”,否定用 Let's not。",
|
||||||
|
body: "“Let’s” is the short form of “let us”. We use it to suggest doing something together with the listener, so the plan includes both people: “Let’s go home.” The negative is “Let’s not”, with “not” placed right after “Let’s”: “Let’s not wait any longer.” A tag question “shall we?” is sometimes added: “Let’s start, shall we?” Friendly answers include “Good idea!”, “OK, let’s.”, or “Sorry, I can’t.”",
|
||||||
|
examples: [
|
||||||
|
"Let’s play football after school.",
|
||||||
|
"It’s late. Let’s not watch another film.",
|
||||||
|
"Let’s ask the teacher, shall we?",
|
||||||
|
],
|
||||||
|
note: "“Let’s” includes the listener (us together). “Let me / let him” is a different pattern: “Let me help you.”",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "___ the door, please. It’s cold.", options: ["Close", "To close", "Closing"], answer: 0, explain: "祈使句用动词原形开头。" },
|
||||||
|
{ q: "___ touch the wet paint!", options: ["Not", "Don’t", "No"], answer: 1, explain: "否定祈使句 → Don’t + 动词。" },
|
||||||
|
{ q: "It’s sunny. ___ go for a walk!", options: ["Let’s", "Let", "Lets"], answer: 0, explain: "提议一起做某事 → Let’s。" },
|
||||||
|
{ q: "___ late for school tomorrow.", options: ["Don’t be", "Not be", "Be not"], answer: 0, explain: "be 的否定祈使 → Don’t be。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "___ me your photo album, please.", options: ["Show", "To show", "Showing"], answer: 0, explain: "礼貌请求仍用动词原形开头。" },
|
||||||
|
{ q: "The baby is sleeping. ___ make noise.", options: ["Not", "Don’t", "No"], answer: 1, explain: "否定祈使 → Don’t make。" },
|
||||||
|
{ q: "___ a suggestion that means “we go together”:", options: ["Let’s dance.", "Let dance.", "Lets we dance."], answer: 0, explain: "Let’s = let us,含听话人。" },
|
||||||
|
{ q: "“Let’s have pizza tonight.” — “___ !”", options: ["Yes, you can", "Good idea", "Don’t be"], answer: 1, explain: "回应建议常用 Good idea。" },
|
||||||
|
{ q: "___ with the glass; it breaks easily.", options: ["Be careful", "Are careful", "To be careful"], answer: 0, explain: "be 的祈使式是原形 Be。" },
|
||||||
|
{ q: "Pick the correct negative:", options: ["No run here.", "Not to run here.", "Don’t run here."], answer: 2, explain: "否定祈使只有 Don’t + 原形。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "Possession: ’s, of, have got / has got",
|
||||||
|
goal: "用 's、of 和 have got 三种方式表达“谁的、属于”。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "The possessive ’s",
|
||||||
|
zh: "在“有生命”的名词后加 's 表示所属。",
|
||||||
|
body: "We add “’s” to a noun to show that something belongs to a person or animal: “my sister’s room”, “the dog’s tail”. For a plural noun that already ends in -s, we add only an apostrophe, with no extra s: “the students’ books”. Irregular plurals that do not end in -s still take the full “’s”: “the children’s toys”, “the women’s coats”. In speech, “’s” sounds just like the plural -s, so only the spelling shows the difference.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Owner", "Form", "Example"],
|
||||||
|
rows: [
|
||||||
|
["one person: Tom", "Tom’s", "Tom’s bike"],
|
||||||
|
["plural in -s: my parents", "parents’", "my parents’ car"],
|
||||||
|
["irregular plural: children", "children’s", "the children’s classroom"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["My dog’s name is Coco.", "Lucy and Lily’s mother is a nurse."],
|
||||||
|
note: "Two owners sharing one thing take one ’s: “Tom and Jerry’s flat”. Separate things take two: “Tom’s and Jerry’s bags”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Possession with of",
|
||||||
|
zh: "无生命事物的所属常用“名词 + of + 名词”。",
|
||||||
|
body: "With things that are not alive — a city, a book, a country, a building — we normally use “of”: “the capital of France”, “the end of the film”, “the colour of the sky”. We usually avoid the “’s” pattern with these, so prefer “the door of the garage” to “the garage’s door”. “Of” simply joins two nouns, with the second noun naming the owner, the source, or the whole that something belongs to.",
|
||||||
|
examples: [
|
||||||
|
"What is the name of your school?",
|
||||||
|
"I love the colours of autumn.",
|
||||||
|
"The roof of the house is red.",
|
||||||
|
],
|
||||||
|
note: "Prefer “the door of the garage”, not “the garage’s door”. Reserve ’s mostly for people and animals.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "have got / has got",
|
||||||
|
zh: "have got 表示“拥有”;he/she/it 用 has got。",
|
||||||
|
body: "“Have got” means exactly the same as “have” when we talk about possession: “I have got a new pencil case.” = “I have a new pencil case.” In speech we nearly always use the short forms: “I’ve got”, “she’s got”, “they’ve got”. With he/she/it the form is “has got”. To make negatives and questions we do not use “do/does”; instead “have/has” itself moves: “Have you got a pen?” “She hasn’t got a bike.”",
|
||||||
|
structure: {
|
||||||
|
cols: ["Subject", "Form", "Example"],
|
||||||
|
rows: [
|
||||||
|
["I / You / We / They", "have got (’ve got)", "They’ve got two cats."],
|
||||||
|
["He / She / It", "has got (’s got)", "She’s got long hair."],
|
||||||
|
["negative", "haven’t / hasn’t got", "I haven’t got any money."],
|
||||||
|
["question", "Have / Has … got?", "Have you got a brother?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["My bike has got a bell.", "We’ve got a test tomorrow."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "’s vs of vs have got: choosing",
|
||||||
|
zh: "人/动物多用 's,事物多用 of,表达“某人拥有”用 have got。",
|
||||||
|
body: "All three tools show a belonging relationship, but they fit different situations. For a person or animal that owns something, “’s” is the shortest: “Ben’s phone”. For non-living wholes and parts, use “of”: “the door of the fridge”. To say simply that someone possesses something, use “have got”: “Ben has got a phone.”",
|
||||||
|
examples: [
|
||||||
|
"My teacher’s name is Mr Wu. / The name of my school is Sunshine.",
|
||||||
|
"I’ve got an idea!",
|
||||||
|
],
|
||||||
|
note: "“Have got” is about owning; it is not used for actions: say “I have breakfast at seven”, not “I’ve got breakfast at seven”.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "This is my ___ bicycle.(sister)", options: ["sister", "sister’s", "sisters of"], answer: 1, explain: "单数人加 ’s:sister’s。" },
|
||||||
|
{ q: "She ___ got a lovely voice.", options: ["have", "has", "is"], answer: 1, explain: "she → has got。" },
|
||||||
|
{ q: "They live in the capital ___ Spain.", options: ["’s", "of", "have"], answer: 1, explain: "无生命所属用 of。" },
|
||||||
|
{ q: "___ you got any pets?", options: ["Have", "Has", "Do got"], answer: 0, explain: "you 的 have got 疑问 → Have you got。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "The ___ playground is very big.(children)", options: ["childrens’", "children’s", "children of"], answer: 1, explain: "不规则复数仍加 ’s:children’s。" },
|
||||||
|
{ q: "My parents ___ got a small farm.", options: ["has", "have", "is"], answer: 1, explain: "parents 复数 → have got。" },
|
||||||
|
{ q: "I love the songs ___ this film.", options: ["’s", "of", "have"], answer: 1, explain: "事物的所属 → of。" },
|
||||||
|
{ q: "“Has he got a sister?” — “Yes, ___ .”", options: ["he has", "he have", "he is"], answer: 0, explain: "has got 疑问的肯定短答 → he has。" },
|
||||||
|
{ q: "These are my ___ gloves.(两个哥哥共用)", options: ["brothers’", "brother’s of", "brother"], answer: 0, explain: "复数 -s 结尾只加撇:brothers’。" },
|
||||||
|
{ q: "She ___ got a ticket for the concert.", options: ["have", "has", "’s have"], answer: 1, explain: "she → has got。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "weekly",
|
||||||
|
cefr: "A1",
|
||||||
|
title: "第 2 周测验",
|
||||||
|
intro: "本周你学了 there be、地点介词、时间介词、can、祈使句与 Let's、所有格。下面 10 题综合检测,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "There ___ a lot of snow outside.", options: ["is", "are", "have"], answer: 0, explain: "snow 不可数 → there is。" },
|
||||||
|
{ q: "The post office is ___ the bank ___ the cinema.", options: ["next to; next to", "between; and", "in front of; and"], answer: 1, explain: "两处之间 → between … and …。" },
|
||||||
|
{ q: "We have English class ___ Monday morning.", options: ["in", "at", "on"], answer: 2, explain: "具体某一天的上午 → on。" },
|
||||||
|
{ q: "The film starts ___ eight o’clock.", options: ["at", "on", "in"], answer: 0, explain: "时刻 → at。" },
|
||||||
|
{ q: "___ I use your dictionary?", options: ["Can", "Do", "Am"], answer: 0, explain: "请求许可 → Can I。" },
|
||||||
|
{ q: "It’s very dark. ___ turn on the light, please.", options: ["To", "Please", "—(直接用动词原形开头)"], answer: 2, explain: "祈使句以动词原形开头:Turn on…;please 只是附加。" },
|
||||||
|
{ q: "___ run in the library!", options: ["Not", "No", "Don’t"], answer: 2, explain: "否定祈使 → Don’t run。" },
|
||||||
|
{ q: "This is my ___ guitar.(father)", options: ["father", "father’s", "father of"], answer: 1, explain: "人作所属加 ’s:father’s。" },
|
||||||
|
{ q: "My little cousin ___ got blue eyes.", options: ["have", "has", "is"], answer: 1, explain: "单数第三人称 → has got。" },
|
||||||
|
{ q: "“Are there any eggs in the fridge?” — “No, ___ .”", options: ["there isn’t", "there aren’t", "they aren’t"], answer: 1, explain: "复数疑问的否定短答 → there aren’t。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,430 @@
|
|||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 第 3 周:A2 拓展 —— 现在进行时、一般现在 vs 现在进行、some/any 与可数/不可数、
|
||||||
|
// how much/many 与 (a) few/(a) little、频率副词与地点副词、一般过去时(规则动词与 -ed 拼写)
|
||||||
|
// 全部讲解、例句、练习、测验均为原创。
|
||||||
|
|
||||||
|
export const week03: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "The present continuous (form and use)",
|
||||||
|
goal: "掌握现在进行时的构成,用来描述此刻正在发生的动作。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Forming the present continuous",
|
||||||
|
zh: "现在进行时 = am/is/are + 动词-ing。",
|
||||||
|
body: "We build the present continuous with the verb “be” (am/is/are) plus the -ing form of the main verb: “I am reading.” “Be” changes with the subject, exactly as you learned in Week 1, while the -ing part never changes. Both parts are needed in every sentence. In speech and informal writing we usually contract the subject and “be”: “I’m reading”, “she’s sleeping”, “they’re playing”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Subject", "be", "verb-ing", "Example"],
|
||||||
|
rows: [
|
||||||
|
["I", "am", "reading", "I am reading a comic."],
|
||||||
|
["He / She / It", "is", "reading", "She is reading in bed."],
|
||||||
|
["You / We / They", "are", "reading", "They are reading the menu."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["It is raining outside.", "We are waiting for the bus."],
|
||||||
|
note: "Never drop the “be”: “I reading” is wrong. The two parts always work together.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Spelling the -ing form",
|
||||||
|
zh: "多数动词直接加 -ing;去 e 加 -ing;重读闭音节双写末尾辅音。",
|
||||||
|
body: "Most verbs simply add “-ing”: “play → playing”, “read → reading”. Verbs ending in a single silent “e” drop that e first: “make → making”, “write → writing”; but verbs ending in -ee just add “-ing”: “see → seeing”. One-syllable verbs that end consonant-vowel-consonant double the final letter: “run → running”, “sit → sitting”. Verbs ending in -ie change it to y: “die → dying”, “lie → lying”.",
|
||||||
|
examples: ["make → making", "write → writing", "swim → swimming", "begin → beginning"],
|
||||||
|
note: "Verbs ending in -w, -x, -y do not double: “snow → snowing”, “play → playing”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "When we use it",
|
||||||
|
zh: "描述说话时正在进行的动作,或近期暂时的情况。",
|
||||||
|
body: "The main use is for actions happening right now, at the very moment of speaking: “Look! The dog is chasing a ball.” “Listen! Someone is singing.” We also use it for temporary situations around this period of time, even if the action is not going on this exact second: “I am reading a great book these days.” “She is staying with us this week.”",
|
||||||
|
examples: [
|
||||||
|
"Be quiet — Dad is on the phone; he is talking to his boss.",
|
||||||
|
"We are staying with Grandma this week.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Negatives and questions",
|
||||||
|
zh: "否定在 be 后加 not;疑问把 be 提到主语前。",
|
||||||
|
body: "To make a negative, add “not” after am/is/are: “I’m not listening.” “They aren’t working.” To make a yes/no question, move “be” in front of the subject: “Are you coming?” “Is it raining?” Question words go before “be”: “What are you doing?” “Where is she going?” Short answers repeat the right form of “be”: “Yes, I am.” / “No, she isn’t.” / “Yes, they are.”",
|
||||||
|
examples: [
|
||||||
|
"The children aren’t sleeping yet.",
|
||||||
|
"Is it still snowing? — No, it isn’t.",
|
||||||
|
"Where are you going?",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "Look! The baby ___ .", options: ["walks", "is walking", "walk"], answer: 1, explain: "Look! 提示此刻正在发生 → is walking。" },
|
||||||
|
{ q: "She ___ a letter now.(write)", options: ["is writing", "is writeing", "writes"], answer: 0, explain: "write 去 e 加 -ing:writing。" },
|
||||||
|
{ q: "They ___ TV at the moment.", options: ["aren’t watch", "aren’t watching", "isn’t watching"], answer: 1, explain: "they → aren’t + watching。" },
|
||||||
|
{ q: "___ you listening to me?", options: ["Do", "Are", "Is"], answer: 1, explain: "you 的进行时疑问 → Are you。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "My dad ___ in the garden right now.", options: ["works", "is working", "work"], answer: 1, explain: "right now → 现在进行时 is working。" },
|
||||||
|
{ q: "It ___ at the moment; take an umbrella.", options: ["rains", "is raining", "rain"], answer: 1, explain: "at the moment → is raining。" },
|
||||||
|
{ q: "The boys ___ football in the yard.(run 的 -ing)", options: ["are runing", "are running", "is running"], answer: 1, explain: "run 双写 n:running;复数主语 → are。" },
|
||||||
|
{ q: "I ___ my homework now; I can’t play.", options: ["am doing", "do", "am do"], answer: 0, explain: "now → am doing。" },
|
||||||
|
{ q: "“Is Mum cooking?” — “Yes, ___ .”", options: ["she does", "she is", "she has"], answer: 1, explain: "进行时短答重复 be:she is。" },
|
||||||
|
{ q: "We ___ to music this evening.", options: ["are listening", "listen", "is listening"], answer: 0, explain: "we → are listening(今晚的临时安排/正在做)。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "Present simple vs present continuous",
|
||||||
|
goal: "区分一般现在时(习惯/事实)与现在进行时(此刻/暂时)。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Habit vs right now",
|
||||||
|
zh: "一般现在时表习惯和事实;现在进行时表此刻或暂时正在做的事。",
|
||||||
|
body: "Use the present simple for things that happen regularly or are always true: “She drinks tea every day.” Use the present continuous for what is happening now or around now: “She is drinking tea — do you want some?” The same activity can appear in both, depending on the time we mean.",
|
||||||
|
examples: [
|
||||||
|
"I walk to school every day. / I am walking to school today because my bike is broken.",
|
||||||
|
"Water boils at 100°C. / The soup is boiling; turn it down.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Signal words",
|
||||||
|
zh: "看时间标志词:every day/usually/often 用一般现在;now/look/at the moment 用进行时。",
|
||||||
|
body: "Time expressions are strong clues, so always look for them first. “Every day, usually, often, always, never, on Mondays” point to the present simple, because they describe routines. “Now, right now, at the moment, look!, listen!, today, this week” point to the present continuous, because they point at the present moment. When you see one of these words in a sentence or a test question, let it guide your choice before anything else.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Clue words", "Tense", "Example"],
|
||||||
|
rows: [
|
||||||
|
["every day / usually / often", "present simple", "He usually cycles to work."],
|
||||||
|
["now / look! / at the moment", "present continuous", "Look! He is cycling past."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["They often play chess. / They are playing chess now."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "State verbs: no continuous",
|
||||||
|
zh: "表示感觉、想法、拥有的动词(like、know、want、have got)通常不用进行时。",
|
||||||
|
body: "Some verbs describe states — feelings, thoughts, senses, possession — rather than actions, so we normally keep them in the present simple even when we mean right now. “I like this song”, not “I am liking this song.” “I know the answer”, not “I am knowing.” Common state verbs to memorise: like, love, hate, want, need, prefer, know, understand, remember, believe, have got.",
|
||||||
|
examples: [
|
||||||
|
"I understand the question now. (not “am understanding”)",
|
||||||
|
"She wants a new phone. (not “is wanting”)",
|
||||||
|
"We have got a dog. (not “are having got”)",
|
||||||
|
],
|
||||||
|
note: "Some verbs have both uses: “I think it’s good” (opinion, simple) vs “I’m thinking about the problem” (mental activity, continuous).",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Asking about routines and the moment",
|
||||||
|
zh: "问习惯用 Do/Does;问此刻用 am/is/are。",
|
||||||
|
body: "The question forms stay completely separate, so do not mix them. For habits and facts we use “do/does”: “What do you do at weekends?” “Does she play tennis?” For the moment we use “be”: “What are you doing?” “Is she playing tennis now?” Notice that the helper is different — “do/does” versus “am/is/are” — while the main verb keeps its tense form: the base form after do/does, or the -ing form after be.",
|
||||||
|
examples: [
|
||||||
|
"Where do you live? (general fact) / Where are you staying this week? (temporary)",
|
||||||
|
"What does he do? (job) / What is he doing? (right now)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She ___ coffee every morning.", options: ["drinks", "is drinking", "drink"], answer: 0, explain: "every morning 表习惯 → drinks。" },
|
||||||
|
{ q: "Be quiet! The baby ___ .", options: ["sleeps", "is sleeping", "sleep"], answer: 1, explain: "此刻正在发生 → is sleeping。" },
|
||||||
|
{ q: "I ___ this film; it’s boring.(like)", options: ["am not liking", "don’t like", "not like"], answer: 1, explain: "like 是状态动词,用一般现在否定。" },
|
||||||
|
{ q: "They ___ chess at the moment.", options: ["play", "are playing", "plays"], answer: 1, explain: "at the moment → are playing。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "My brother ___ to school by bike every day.", options: ["goes", "is going", "go"], answer: 0, explain: "every day 习惯 → goes。" },
|
||||||
|
{ q: "Look! Someone ___ at the door.", options: ["knocks", "is knocking", "knock"], answer: 1, explain: "Look! → is knocking。" },
|
||||||
|
{ q: "___ she ___ French? (她会说吗,一般能力/事实)", options: ["Is; speaking", "Does; speak", "Do; speak"], answer: 1, explain: "一般事实/能力 → Does she speak。" },
|
||||||
|
{ q: "We ___ TV right now.", options: ["watch", "are watching", "watches"], answer: 1, explain: "right now → are watching。" },
|
||||||
|
{ q: "I ___ the answer.(know)", options: ["am knowing", "know", "knows"], answer: 1, explain: "know 状态动词 → 一般现在 know。" },
|
||||||
|
{ q: "He usually ___ lunch at home, but today he ___ in a café.", options: ["has; is having", "is having; has", "has; has"], answer: 0, explain: "usually → has;today(临时)→ is having。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "some / any and countable / uncountable nouns",
|
||||||
|
goal: "区分可数与不可数名词,正确使用 some 与 any。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Countable and uncountable nouns",
|
||||||
|
zh: "可数名词能一个一个数,有单复数;不可数名词不能数,通常只用单数。",
|
||||||
|
body: "Countable nouns are things we can count one by one: “one apple, two apples”. They have a plural form. Uncountable nouns are materials, liquids, or ideas we treat as a whole: “water, bread, rice, information, money”. They usually have no plural and take a singular verb. To count them we add a unit: “a glass of water, two pieces of bread”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Type", "Examples", "How to count"],
|
||||||
|
rows: [
|
||||||
|
["countable", "apple, chair, idea", "two apples, three chairs"],
|
||||||
|
["uncountable", "water, bread, money", "a glass of water, a loaf of bread"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I’d like some rice.", "There are six chairs in the kitchen."],
|
||||||
|
note: "Some words differ from Chinese: “furniture”, “advice”, “homework”, “money” are uncountable in English — no plural -s.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "some in positive sentences",
|
||||||
|
zh: "肯定句中,表示“一些”用 some(可数复数和不可数都可以)。",
|
||||||
|
body: "We use “some” in positive sentences to mean an unspecified amount or number — we do not say exactly how much. It works both with plural countable nouns and with uncountable nouns: “some books”, “some milk”, “some friends”. With a singular countable noun, “some” has a different flavour and means “a certain one that I do not name”: “Some man called for you this morning.” At this level, focus on the ordinary “some = 一些” use.",
|
||||||
|
examples: [
|
||||||
|
"There are some eggs in the fridge.",
|
||||||
|
"I need some help with this.",
|
||||||
|
"She bought some bananas.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "any in negatives and questions",
|
||||||
|
zh: "否定句和疑问句中,表示“一些/任何”用 any。",
|
||||||
|
body: "In negative sentences and in most questions we use “any”: “I haven’t got any money.” “Are there any oranges left?” “Any” stresses that the amount is open — it may even be zero. In positive sentences “any” changes meaning to “it doesn’t matter which one”: “Pick any seat you like.” Remember the big exception: polite offers and requests keep “some”, because we hope for the answer “yes”: “Would you like some cake?”",
|
||||||
|
examples: [
|
||||||
|
"There aren’t any buses after ten.",
|
||||||
|
"Have you got any brothers or sisters?",
|
||||||
|
"Any colour is fine with me.",
|
||||||
|
],
|
||||||
|
note: "Offers and requests usually keep “some”: “Would you like some tea?” “Can I have some water, please?”",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "a / an and no article with uncountables",
|
||||||
|
zh: "不可数名词前不用 a/an;可数单数名词通常需要冠词。",
|
||||||
|
body: "Because uncountable nouns cannot be counted as “one”, we never put “a/an” directly in front of them: “a bread” and “a money” are wrong — say “some bread” or “a piece of bread”, “some money” or “a coin”. To count uncountables we add a unit word: “a glass of water”, “two bottles of milk”. Singular countable nouns, by contrast, almost always need a word in front: “a chair”, “the table”, “my book” — a bare “I have book” is wrong.",
|
||||||
|
examples: [
|
||||||
|
"I had some toast for breakfast. (not “a toast”)",
|
||||||
|
"She gave me a useful piece of advice.",
|
||||||
|
"There is a lamp on the desk.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "There is ___ milk in the fridge.", options: ["some", "any", "a"], answer: 0, explain: "肯定句+不可数 → some。" },
|
||||||
|
{ q: "Have you got ___ questions?", options: ["some", "any", "a"], answer: 1, explain: "疑问句 → any。" },
|
||||||
|
{ q: "We haven’t got ___ bread.", options: ["some", "any", "one"], answer: 1, explain: "否定句 → any。" },
|
||||||
|
{ q: "She gave me ___ useful advice.", options: ["an", "some", "a"], answer: 1, explain: "advice 不可数,不用 a/an → some。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "Would you like ___ tea? (礼貌提供)", options: ["any", "some", "a"], answer: 1, explain: "提议/邀请用 some。" },
|
||||||
|
{ q: "There aren’t ___ chairs in the room.", options: ["some", "any", "one"], answer: 1, explain: "否定句复数 → any。" },
|
||||||
|
{ q: "I need to buy ___ furniture.", options: ["some", "a", "many"], answer: 0, explain: "furniture 不可数 → some。" },
|
||||||
|
{ q: "We need ___ information before we decide.", options: ["an", "some", "a few"], answer: 1, explain: "information 不可数 → some。" },
|
||||||
|
{ q: "___ child can do this puzzle.(任意一个)", options: ["Any", "Some", "Much"], answer: 0, explain: "肯定句表“任意” → Any。" },
|
||||||
|
{ q: "She has got ___ money, but not much.", options: ["any", "some", "an"], answer: 1, explain: "肯定句不可数 → some。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "how much / how many and (a) few / (a) little",
|
||||||
|
goal: "用 how much / how many 提问数量,区分 few / a few / little / a little。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "how many for countable nouns",
|
||||||
|
zh: "问可数名词的数量用 how many + 复数名词。",
|
||||||
|
body: "When we ask about the number of things we can count, we use “how many” followed by a plural noun: “How many apples do you want?” “How many brothers has she got?” The noun after “many” is always plural — never “how many apple”. The answer is a number or a quantity expression: “Three.” / “A few.” / “About twenty.” In informal speech the noun is sometimes dropped when it is obvious: “How many did you buy?”",
|
||||||
|
examples: [
|
||||||
|
"How many students are in your class?",
|
||||||
|
"How many eggs do we need for the cake?",
|
||||||
|
"How many languages can you speak?",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "how much for uncountable nouns",
|
||||||
|
zh: "问不可数名词的数量用 how much;how much 也问价格。",
|
||||||
|
body: "For things we cannot count, we use “how much” followed by the uncountable noun: “How much water is left?” “How much time do we have?” “How much” also asks about price, even with countable things: “How much is this T-shirt?” “How much are these shoes?” Note that the verb agrees with the noun that follows: with an uncountable noun we use singular “is” — “How much money is there?” — and there is never a plural, so no “moneys”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Question", "Noun type", "Example"],
|
||||||
|
rows: [
|
||||||
|
["how many", "countable plural", "How many coins are there?"],
|
||||||
|
["how much", "uncountable", "How much money have you got?"],
|
||||||
|
["how much (price)", "—", "How much are the tickets?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["How much sugar do you take in your tea?", "How much time do we have?"],
|
||||||
|
note: "“How much” asks amount; “how many” asks number. “How much friends” is wrong — say “how many friends”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "few / a few (countable)",
|
||||||
|
zh: "a few = 有一些(肯定语气);few = 很少、几乎没有(否定语气)。",
|
||||||
|
body: "Both “few” and “a few” are used only with plural countable nouns. “A few” means a small number, but enough — it carries a positive, comfortable feeling: “I’ve got a few friends here, so I’m not lonely.” “Few” without the “a” means not many, almost not enough — a more negative, disappointing feeling: “Few people came to the meeting; the hall was nearly empty.” One tiny word “a” flips the emotion of the whole sentence.",
|
||||||
|
examples: [
|
||||||
|
"There are a few biscuits left — have one.",
|
||||||
|
"Few students finished the hard test.",
|
||||||
|
],
|
||||||
|
note: "The tiny word “a” changes the feeling: “a few” = 还好有一些;“few” = 少得可怜。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "little / a little (uncountable)",
|
||||||
|
zh: "a little = 有一点(肯定);little = 几乎没有(否定),都接不可数名词。",
|
||||||
|
body: "“A little” and “little” work with uncountable nouns in the same way. “A little” = a small amount, but some: “There is a little milk; enough for one cup.” “Little” = hardly any, not enough: “There is little hope of good weather.” Match these with uncountable nouns, and few/a few with countable ones.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Word", "Noun type", "Feeling"],
|
||||||
|
rows: [
|
||||||
|
["a few", "countable plural", "positive: some, enough"],
|
||||||
|
["few", "countable plural", "negative: almost none"],
|
||||||
|
["a little", "uncountable", "positive: some, enough"],
|
||||||
|
["little", "uncountable", "negative: almost none"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I have a little time before my lesson.", "We had little rain this summer; the garden is dry."],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "___ apples did you buy?", options: ["How much", "How many", "How"], answer: 1, explain: "apples 可数 → how many。" },
|
||||||
|
{ q: "___ water is in the bottle?", options: ["How many", "How much", "How few"], answer: 1, explain: "water 不可数 → how much。" },
|
||||||
|
{ q: "Don’t worry, we’ve still got ___ time.", options: ["a few", "a little", "few"], answer: 1, explain: "time 不可数+肯定语气 → a little。" },
|
||||||
|
{ q: "___ people know this secret, so keep it quiet.(没几个人)", options: ["A few", "Few", "A little"], answer: 1, explain: "可数+否定语气(几乎没有)→ Few。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "___ brothers and sisters have you got?", options: ["How much", "How many", "How little"], answer: 1, explain: "兄弟姐妹可数 → how many。" },
|
||||||
|
{ q: "___ does this book cost?", options: ["How many", "How much", "How few"], answer: 1, explain: "问价格 → how much。" },
|
||||||
|
{ q: "___ students passed the hard test; most of them failed.(几乎没有人)", options: ["A few", "Few", "A little"], answer: 1, explain: "students 可数,“几乎没有人”是否定语气 → Few(不带 a)。" },
|
||||||
|
{ q: "Add ___ salt to the soup.(少许,肯定)", options: ["a little", "few", "a few"], answer: 0, explain: "salt 不可数+肯定 → a little。" },
|
||||||
|
{ q: "There are ___ good films on TV tonight, so let’s watch one.(有一些)", options: ["few", "little", "a few"], answer: 2, explain: "films 可数+肯定 → a few。" },
|
||||||
|
{ q: "___ money do you have in your pocket?", options: ["How many", "How much", "How a little"], answer: 1, explain: "money 不可数 → how much。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "Adverbs of frequency and adverbs of place",
|
||||||
|
goal: "用频率副词描述事情发生的频繁程度,用地点副词说明方向与位置。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Adverbs of frequency",
|
||||||
|
zh: "always/usually/often/sometimes/never 表示从“总是”到“从不”的频率。",
|
||||||
|
body: "Adverbs of frequency tell us how often something happens, on a scale from 100% down to 0%. A common classroom scale: always (100%), usually (about 80%), often (about 60%), sometimes (about 40%), hardly ever (about 10%), never (0%). We use them mostly with the present simple, because habits and routines are exactly what they describe: “She always gets up early.” “I sometimes ride my bike to school.” “He never eats breakfast.”",
|
||||||
|
structure: {
|
||||||
|
cols: ["Adverb", "Roughly", "Example"],
|
||||||
|
rows: [
|
||||||
|
["always", "100%", "She always brushes her teeth."],
|
||||||
|
["usually", "~80%", "We usually walk to school."],
|
||||||
|
["often", "~60%", "He often reads before bed."],
|
||||||
|
["sometimes", "~40%", "I sometimes help my dad cook."],
|
||||||
|
["never", "0%", "They never eat meat."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["My cat sometimes sleeps on my homework.", "It never snows on this island."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Where the adverb goes",
|
||||||
|
zh: "频率副词放在实义动词之前、be 动词之后。",
|
||||||
|
body: "The position rule is important. With ordinary verbs, the adverb goes before the verb: “She often sings.” With the verb “be”, it goes after: “He is always late.” With a helper plus main verb, it goes after the helper: “I can never remember names.” “Sometimes” is flexible and can also start a sentence.",
|
||||||
|
examples: [
|
||||||
|
"They usually finish at four. (before main verb)",
|
||||||
|
"You are never ready on time! (after be)",
|
||||||
|
"Sometimes we eat out. (sentence start)",
|
||||||
|
],
|
||||||
|
note: "“never” already means “not ever”, so don’t add another negative: “I never go”, not “I don’t never go”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Asking about frequency",
|
||||||
|
zh: "问频率用 How often…?",
|
||||||
|
body: "To ask how frequently something happens, we use “How often…?”, with the normal present-simple question order: “How often do you go swimming?” “How often does he phone home?” Typical answers use the frequency adverbs above, or counting expressions such as “once a week”, “twice a month”, “three times a year”, “every day”. For example: “How often do you visit your grandparents?” — “About twice a month.” Note that “time” takes -s in “three times”.",
|
||||||
|
examples: [
|
||||||
|
"How often does the bus come? — Every ten minutes.",
|
||||||
|
"How often do you go swimming? — Almost never.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Adverbs of place",
|
||||||
|
zh: "here/there/home/upstairs 等地点副词直接放在动词后,不加介词。",
|
||||||
|
body: "Adverbs of place tell us where something is or where someone goes. Common ones: here, there, home, upstairs, downstairs, inside, outside, abroad, everywhere. They usually come after the verb or at the end of the sentence. Notice that “home” here is an adverb, so we say “go home” with no “to”.",
|
||||||
|
examples: [
|
||||||
|
"Come here, please.",
|
||||||
|
"The children are playing outside.",
|
||||||
|
"She went upstairs to get her coat.",
|
||||||
|
"I looked everywhere for my keys.",
|
||||||
|
],
|
||||||
|
note: "“go home / arrive home / get home” take no preposition, because home is acting as an adverb of place.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "He is ___ late for class.", options: ["always", "often be", "very often"], answer: 0, explain: "频率副词放 be 之后:is always。" },
|
||||||
|
{ q: "She ___ drinks milk.(她很少不喝,常喝)", options: ["usually", "is usually", "usually is"], answer: 0, explain: "实义动词前:usually drinks。" },
|
||||||
|
{ q: "It’s cold; let’s go ___ .", options: ["to inside", "inside", "in to"], answer: 1, explain: "inside 是地点副词,不加介词。" },
|
||||||
|
{ q: "___ do you ride a bike? — Every day.", options: ["How much", "How often", "How many"], answer: 1, explain: "问频率 → How often。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "They ___ play football on Sundays.", options: ["often", "are often", "often are"], answer: 0, explain: "实义动词 play 前 → often play。" },
|
||||||
|
{ q: "My room is ___ tidy; I clean it every day.", options: ["always", "always be", "be always"], answer: 0, explain: "be 之后:is always。" },
|
||||||
|
{ q: "She ___ eats sweets; she hates them.", options: ["always", "never", "often"], answer: 1, explain: "讨厌糖果 → 从不 never。" },
|
||||||
|
{ q: "Let’s go ___ ; it’s time for dinner.", options: ["to home", "home", "at home"], answer: 1, explain: "home 作副词,go home 无介词。" },
|
||||||
|
{ q: "I can ___ find my glasses in the morning.", options: ["never", "not never", "never not"], answer: 0, explain: "never 本身含否定,不再加 not。" },
|
||||||
|
{ q: "The keys were ___ ; I searched the whole house.", options: ["everywhere", "nowhere here", "somewhere and anywhere"], answer: 0, explain: "各处都找了 → everywhere。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "The past simple: regular verbs and -ed spelling",
|
||||||
|
goal: "掌握规则动词过去式的构成与 -ed 拼写、读音规则,用于描述过去的事。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "When we use the past simple",
|
||||||
|
zh: "一般过去时表示过去某个时间发生、已结束的动作或状态。",
|
||||||
|
body: "We use the past simple for actions and states that finished at a definite time in the past. Typical clue words include “yesterday, last week, in 2020, two days ago, when I was young”. If you can point to a finished time, you probably need this tense. One nice thing: the same past form is used for all subjects — I, you, he, they — so this time there is no -s problem to worry about.",
|
||||||
|
examples: [
|
||||||
|
"I visited my cousins last Sunday.",
|
||||||
|
"She was very tired after the trip.",
|
||||||
|
"They played basketball yesterday evening.",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Forming regular past tenses with -ed",
|
||||||
|
zh: "规则动词过去式在词尾加 -ed,所有人称相同。",
|
||||||
|
body: "Most verbs form the past simple by adding “-ed”: “walk → walked”, “clean → cleaned”. This one form works for every subject: “I walked”, “she walked”, “they walked”. For negatives and questions we bring in the helper “did” (negative “didn’t”), and — this is the key rule — the main verb then returns to its base form: “She didn’t walk”, “Did they walk?”, never “didn’t walked” or “Did they walked”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Form", "Structure", "Example"],
|
||||||
|
rows: [
|
||||||
|
["positive", "subject + verb-ed", "We watched a film."],
|
||||||
|
["negative", "subject + didn’t + base", "We didn’t watch TV."],
|
||||||
|
["question", "Did + subject + base?", "Did you watch the match?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["He cleaned his room this morning.", "Did she call you? — No, she didn’t."],
|
||||||
|
note: "After “did / didn’t” the verb is base form: “Did you go”, never “Did you went”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Spelling rules for -ed",
|
||||||
|
zh: "-e 结尾只加 -d;辅音+y 变 ied;重读闭音节双写末尾辅音。",
|
||||||
|
body: "Verbs ending in “e” just add “d”: “live → lived”, “dance → danced”. Verbs ending in consonant + y change y to i and add “ed”: “study → studied”; but vowel + y just adds “ed”: “play → played”. One-syllable verbs ending consonant-vowel-consonant double the last letter: “stop → stopped”, “plan → planned”.",
|
||||||
|
examples: ["like → liked", "try → tried", "enjoy → enjoyed", "drop → dropped"],
|
||||||
|
note: "No doubling after w, x, y: “snow → snowed”, “fix → fixed”. Verbs ending in -c add -cked: “picnic → picnicked”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Pronouncing -ed: /t/, /d/, /ɪd/",
|
||||||
|
zh: "-ed 有三种读音:清辅音后读 /t/,浊辅音和元音后读 /d/,t/d 结尾读 /ɪd/。",
|
||||||
|
body: "The ending “-ed” is not always pronounced the same. After a voiceless sound (p, k, f, s, sh, ch) it sounds /t/: “walked, laughed”. After a voiced sound or a vowel it sounds /d/: “played, cleaned”. After t or d we add a whole extra syllable /ɪd/: “wanted, needed”. This helps your speech sound natural.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Verb ends in", "-ed sounds", "Examples"],
|
||||||
|
rows: [
|
||||||
|
["voiceless (p/k/f/s/sh/ch)", "/t/", "stopped, watched"],
|
||||||
|
["voiced / vowel", "/d/", "called, played"],
|
||||||
|
["t or d", "/ɪd/", "started, decided"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["She laughed at the joke. /t/", "He needed more time. /ɪd/"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "We ___ a great film last night.(watch)", options: ["watched", "watch", "watching"], answer: 0, explain: "last night → 过去式 watched。" },
|
||||||
|
{ q: "She ___ to the park yesterday.(go 的过去式)", options: ["goed", "went", "gone"], answer: 1, explain: "go 是不规则动词,过去式 went;gone 是过去分词,不能单独作谓语。" },
|
||||||
|
{ q: "He ___ his homework an hour ago.(finish)", options: ["finish", "finished", "finishied"], answer: 1, explain: "finish 加 -ed:finished。" },
|
||||||
|
{ q: "___ you see Tom at the party?", options: ["Did", "Do", "Were"], answer: 0, explain: "过去式疑问用 Did + 原形。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "They ___ football after school yesterday.", options: ["play", "played", "playing"], answer: 1, explain: "yesterday → played。" },
|
||||||
|
{ q: "She ___ all night for the test.(study)", options: ["studyed", "studied", "studdied"], answer: 1, explain: "辅音+y → i+ed:studied。" },
|
||||||
|
{ q: "We ___ the bus and walked home.(stop 的过去式)", options: ["stoped", "stopped", "stoppd"], answer: 1, explain: "重读闭音节双写 p:stopped。" },
|
||||||
|
{ q: "He ___ want any cake.", options: ["didn’t", "doesn’t", "not"], answer: 0, explain: "过去否定 → didn’t + 原形 want。" },
|
||||||
|
{ q: "___ she arrive on time?", options: ["Does", "Did", "Was"], answer: 1, explain: "过去疑问 → Did + 原形 arrive。" },
|
||||||
|
{ q: "Which word’s -ed is pronounced /ɪd/?", options: ["played", "wanted", "laughed"], answer: 1, explain: "以 t/d 结尾加读 /ɪd/:wanted。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "weekly",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "第 3 周测验",
|
||||||
|
intro: "本周你学了现在进行时、一般现在 vs 现在进行、some/any 与可数/不可数、how much/many 与 few/little、频率与地点副词、一般过去时。下面 10 题综合检测,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "Look! The children ___ kites in the park.", options: ["fly", "are flying", "flies"], answer: 1, explain: "Look! → 现在进行时 are flying。" },
|
||||||
|
{ q: "My dad ___ tea every morning.", options: ["is drinking", "drinks", "drink"], answer: 1, explain: "every morning 习惯 → drinks。" },
|
||||||
|
{ q: "I ___ this song; it’s my favourite.(like)", options: ["am liking", "like", "likes"], answer: 1, explain: "like 状态动词 → 一般现在 like。" },
|
||||||
|
{ q: "There isn’t ___ juice in the glass.", options: ["some", "any", "a"], answer: 1, explain: "否定句 → any。" },
|
||||||
|
{ q: "Would you like ___ coffee?", options: ["any", "some", "many"], answer: 1, explain: "礼貌提供 → some。" },
|
||||||
|
{ q: "___ eggs do we need for the cake?", options: ["How much", "How many", "How little"], answer: 1, explain: "eggs 可数 → how many。" },
|
||||||
|
{ q: "___ people came to the talk; the room was almost empty.(没几个人)", options: ["A few", "Few", "A little"], answer: 1, explain: "people 可数,“几乎空了”表示否定语气 → Few(不带 a)。" },
|
||||||
|
{ q: "She is ___ late; she always arrives early.", options: ["never", "always", "often"], answer: 0, explain: "总是早到 → 从不 never;放 be 之后。" },
|
||||||
|
{ q: "It’s raining; let’s stay ___ .", options: ["to inside", "inside", "in to"], answer: 1, explain: "inside 是地点副词,无介词。" },
|
||||||
|
{ q: "We ___ to the museum last Saturday.(go)", options: ["goed", "went", "gone"], answer: 1, explain: "go 的过去式是不规则 went。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 第 4 周:A2 进阶 —— 一般过去时(不规则动词、否定与疑问)、was/were 与 there was/were、
|
||||||
|
// 过去进行时、used to、比较级形容词。
|
||||||
|
// 全部讲解、例句、练习、测验均为原创,仅使用语法主题名称。
|
||||||
|
|
||||||
|
export const week04: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "Past simple: common irregular verbs",
|
||||||
|
goal: "会用常见不规则动词的过去式,讲述已经发生过的事。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "What the past simple means",
|
||||||
|
zh: "一般过去时表示已结束、不延续到现在的动作。",
|
||||||
|
body: "We use the past simple to talk about actions and situations that finished at a definite time in the past. The action is over. It does not continue into the present. Often a time word tells us when: yesterday, last Friday, in 2019, three years ago. Sometimes the time is simply understood because we are telling a story. The past simple is the main tense for stories and for talking about your day.",
|
||||||
|
examples: ["I finished my homework an hour ago.", "We visited Shanghai last summer."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Regular verbs just add -ed",
|
||||||
|
zh: "规则动词的过去式在词尾加 -ed,拼写有几条小规则。",
|
||||||
|
body: "Many verbs are regular: we add -ed to the base form. The spelling needs a little care. If a short verb ends in one vowel plus one consonant, we double the consonant: stop → stopped, plan → planned. A consonant plus -y changes to -ied: study → studied, carry → carried. Verbs already ending in -e simply add -d: like → liked, dance → danced. Say each new form aloud and you will soon feel the pattern.",
|
||||||
|
examples: ["She watched a film after dinner.", "He studied until midnight.", "They stopped at the red light."],
|
||||||
|
note: "play → played(y 前是元音,直接加 -ed);study → studied(辅音 + y,变 ied)。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Irregular verbs must be memorised",
|
||||||
|
zh: "最常用的动词往往不规则,只能像生词一样逐个记住。",
|
||||||
|
body: "Many of the most common verbs are irregular: their past forms do not end in -ed, and there is no single rule. You learn them one by one, like new words. Grouping helps. Some change their vowel: see → saw, give → gave, write → wrote. Some change completely: go → went, buy → bought, think → thought. A few never change at all: cut → cut, put → put. Learning ten at a time is much easier than fifty.",
|
||||||
|
structure: {
|
||||||
|
cols: ["base form", "past simple", "example"],
|
||||||
|
rows: [
|
||||||
|
["go", "went", "She went home early."],
|
||||||
|
["see", "saw", "I saw a huge bird."],
|
||||||
|
["eat", "ate", "He ate two bowls of rice."],
|
||||||
|
["come", "came", "They came by bus."],
|
||||||
|
["take", "took", "Mum took a photo of us."],
|
||||||
|
["have", "had", "We had fish for lunch."],
|
||||||
|
["buy", "bought", "I bought a new pencil case."],
|
||||||
|
["read", "read", "He read the whole book in a day."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
note: "read 的过去式拼写不变,但读音变成 /red/。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Past time words",
|
||||||
|
zh: "过去时间词帮听者定位:ago 要放在时间段后面。",
|
||||||
|
body: "Past time words help the listener place the action. Common ones are yesterday, last night, last week, last year, two days ago, in 2020, and when I was little. The small word ago always comes after the time period: three days ago, a long time ago. These phrases usually sit at the end of the sentence, though sometimes we move them to the front for emphasis: Yesterday I met our old teacher at the market.",
|
||||||
|
examples: ["She called me two hours ago.", "Last Sunday we climbed the hill behind our school.", "When I was little, I loved dinosaurs."],
|
||||||
|
note: "单独作时间状语说 three days ago,不说 three days before;before 需要参照点,如 three days before the trip。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "Yesterday she ___ (go) to the library.", options: ["go", "went", "goed"], answer: 1, explain: "go 的过去式是不规则变化:went。" },
|
||||||
|
{ q: "They ___ (study) hard last term.", options: ["studyed", "studied", "studys"], answer: 1, explain: "辅音 + y 结尾变 ied:studied。" },
|
||||||
|
{ q: "He ___ (buy) a red hat last week.", options: ["buyed", "bought", "buying"], answer: 1, explain: "buy 的过去式是 bought。" },
|
||||||
|
{ q: "I ___ my grandma three days ___ .", options: ["see / ago", "saw / ago", "saw / before"], answer: 1, explain: "过去式 + ago:saw … three days ago。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "We ___ a great film last night.", options: ["seed", "saw", "see"], answer: 1, explain: "see 的过去式是 saw。" },
|
||||||
|
{ q: "The train ___ at nine yesterday morning.", options: ["left", "leaved", "leave"], answer: 0, explain: "leave 的过去式是 left。" },
|
||||||
|
{ q: "She ___ me a birthday card.", options: ["sended", "send", "sent"], answer: 2, explain: "send 的过去式是 sent。" },
|
||||||
|
{ q: "My dad ___ the car this morning.", options: ["wash", "washed", "washing"], answer: 1, explain: "wash 是规则动词,加 -ed:washed。" },
|
||||||
|
{ q: "Tom ___ his key, so he couldn’t open the door.", options: ["losed", "lose", "lost"], answer: 2, explain: "lose 的过去式是 lost。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "Past simple: negatives and questions (did / didn’t)",
|
||||||
|
goal: "用 did / didn’t 造过去时的否定句和疑问句,记住动词回原形。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Negatives with didn’t",
|
||||||
|
zh: "否定句用 didn’t + 动词原形,过去意义已装进 didn’t。",
|
||||||
|
body: "To make a negative sentence in the past simple, we use did not (didn’t) plus the base form of the main verb. The past meaning already lives inside didn’t, so the main verb does not take -ed and does not take an irregular past form. This rule is the same for every subject: I, you, he, she, we, they all use didn’t. Only the verb be behaves differently, and we meet it in the next lesson.",
|
||||||
|
structure: {
|
||||||
|
cols: ["sentence type", "form", "example"],
|
||||||
|
rows: [
|
||||||
|
["positive", "past form", "She played tennis."],
|
||||||
|
["negative", "didn’t + base", "She didn’t play tennis."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I didn’t sleep well last night.", "He didn’t come to the party.", "We didn’t know the answer."],
|
||||||
|
note: "常见错误:she didn’t went / he didn’t played。didn’t 后面永远用动词原形。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Yes/No questions with Did",
|
||||||
|
zh: "一般疑问句把 Did 放句首,动词用原形,短答语重复 did。",
|
||||||
|
body: "For yes/no questions we put Did at the front, then the subject, then the base form of the verb. Short answers repeat the helper: Yes, I did. / No, she didn’t. We normally do not answer with a bare yes or no — the short answer with did sounds friendly and complete. In a longer answer we switch back to the positive past form: Yes, I did. I saw the film twice.",
|
||||||
|
examples: ["Did you watch the match? — Yes, I did.", "Did she enjoy the trip? — No, she didn’t."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Wh- questions in the past",
|
||||||
|
zh: "特殊疑问句 = 疑问词 + did + 主语 + 动词原形;who 作主语例外。",
|
||||||
|
body: "To ask for information we put a question word in front of Did: Where did you go? What did he say? Why did they leave early? The order is question word + did + subject + base verb. Who can also be the subject of the question. In that case there is no did at all, and the verb keeps its past form: Who ate my cake? — never Who did eat my cake?",
|
||||||
|
examples: ["Where did you go on holiday?", "What time did the film start?", "Who broke the window?"],
|
||||||
|
note: "who 作主语不加 did:Who came?;who 作宾语要加 did:Who did you invite?",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "One rule: did + base form",
|
||||||
|
zh: "只要 did / didn’t 一出现,主动词就回到原形。",
|
||||||
|
body: "Negatives and questions share one golden rule: once did or didn’t appears, the main verb returns to its base form. Think of did as a suitcase that carries all the past meaning, leaving the main verb light and empty. The past form appears only in positive sentences. Practise switching between the three: I saw a fox. → I didn’t see a fox. → Did you see a fox? Master this chain and you have mastered the whole pattern.",
|
||||||
|
examples: ["She wrote a song. → She didn’t write a song.", "They flew to Hainan. → Did they fly to Hainan?"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "He ___ not finish his lunch.", options: ["did", "does", "was"], answer: 0, explain: "过去时否定用 didn’t。" },
|
||||||
|
{ q: "___ you see the rainbow?", options: ["Do", "Did", "Were"], answer: 1, explain: "过去时一般疑问句用 Did。" },
|
||||||
|
{ q: "Where did she ___ the bag?", options: ["found", "find", "finds"], answer: 1, explain: "did 后面用动词原形 find。" },
|
||||||
|
{ q: "Who ___ your cake?", options: ["did eat", "ate", "eat"], answer: 1, explain: "who 作主语,动词直接用过去式 ate。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "We ___ go to the beach because it rained.", options: ["didn’t", "don’t", "weren’t"], answer: 0, explain: "go 是行为动词,过去否定用 didn’t。" },
|
||||||
|
{ q: "Did Tom ___ you his bike?", options: ["lent", "lend", "lending"], answer: 1, explain: "Did 后面用原形 lend。" },
|
||||||
|
{ q: "What ___ they eat for dinner?", options: ["did", "do", "were"], answer: 0, explain: "过去时疑问用 did。" },
|
||||||
|
{ q: "___ she tell you the news? — No, she ___ .", options: ["Does / doesn’t", "Did / didn’t", "Did / don’t"], answer: 1, explain: "Did 提问,短答语也用 didn’t。" },
|
||||||
|
{ q: "Who ___ the door just now?", options: ["did open", "open", "opened"], answer: 2, explain: "who 作主语,动词用过去式 opened。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "was / were and there was / there were",
|
||||||
|
goal: "用 was / were 描述过去的状态与地点,用 there was / were 说“当时有”。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Two past forms of “be”",
|
||||||
|
zh: "be 的过去式有两个:was(单数)和 were(复数)。",
|
||||||
|
body: "The verb be has two past forms: was and were. I, he, she, it, and singular nouns take was. You, we, they, and plural nouns take were. Notice that you always takes were, even when it means one person. The past of be describes a past state, feeling, or place, where no other action verb is present in the sentence. Choose the form by the subject, exactly as in the present: am and is become was, are becomes were.",
|
||||||
|
structure: {
|
||||||
|
cols: ["subject", "past of be", "example"],
|
||||||
|
rows: [
|
||||||
|
["I / he / she / it", "was", "He was at the library."],
|
||||||
|
["you / we / they", "were", "We were hungry."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I was excited about the trip.", "The weather was awful yesterday.", "My grandparents were farmers."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Negatives and questions",
|
||||||
|
zh: "否定加 not(wasn’t / weren’t);疑问把 was / were 提前。",
|
||||||
|
body: "Negatives add not: was not (wasn’t), were not (weren’t). For questions we move was or were in front of the subject. Short answers repeat the verb: Yes, it was. / No, they weren’t. Unlike action verbs, sentences with be never use did — be does the whole job by itself. This makes it simpler than the ordinary past simple, but learners still mix the two systems up, so keep them clearly separate in your head.",
|
||||||
|
examples: ["She wasn’t happy with the result.", "Were you at home at eight? — Yes, I was."],
|
||||||
|
note: "be 动词句不加 did:不说 Did you be happy?,而说 Were you happy?",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "there was / there were",
|
||||||
|
zh: "there was(单数/不可数)、there were(复数)表示“当时有”。",
|
||||||
|
body: "To say that something existed in a place in the past, we use there was for one thing or uncountable things, and there were for many things. The real subject follows the verb, so we match was or were to that noun: There was a cat on the roof. There were many cats on the roof. In questions we swap the two words: Was there a park here? Negatives: There wasn’t any milk left.",
|
||||||
|
structure: {
|
||||||
|
cols: ["", "singular / uncountable", "plural"],
|
||||||
|
rows: [
|
||||||
|
["positive", "There was a hill.", "There were two hills."],
|
||||||
|
["negative", "There wasn’t a hill.", "There weren’t any hills."],
|
||||||
|
["question", "Was there a hill?", "Were there any hills?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["There was a big tree here ten years ago.", "There were thirty students in my old class."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Choosing was/were or did",
|
||||||
|
zh: "句子里没有行为动词用 was/were,有行为动词用 did。",
|
||||||
|
body: "Here is the question learners ask most: in a past question, do we use was/were or did? The answer depends on the main verb. If there is no action verb, and the sentence is about a state, place, or feeling, use was/were: Where were you? How was the film? If there is an action verb, use did with the base verb: Where did you go? Did you like the film? Keep the two tools in different boxes.",
|
||||||
|
examples: ["Why were you late? (no action verb)", "Why did you come late? (action verb come)"],
|
||||||
|
note: "别混淆:Was the film good?(状态)与 Did you like the film?(行为)都是对的,但不能写成 Did the film be good?",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "The exam ___ very difficult.", options: ["was", "were", "did"], answer: 0, explain: "exam 单数且是状态,用 was。" },
|
||||||
|
{ q: "___ there many people at the concert?", options: ["Was", "Were", "Did"], answer: 1, explain: "people 复数 → Were there。" },
|
||||||
|
{ q: "Where ___ you last night?", options: ["did", "was", "were"], answer: 2, explain: "you + 状态/地点 → were。" },
|
||||||
|
{ q: "There ___ any hot water in the bottle.", options: ["wasn’t", "weren’t", "didn’t"], answer: 0, explain: "water 不可数 → wasn’t。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "My shoes ___ wet after the rain.", options: ["were", "was", "is"], answer: 0, explain: "shoes 复数 → were。" },
|
||||||
|
{ q: "___ she a nurse ten years ago?", options: ["Did", "Were", "Was"], answer: 2, explain: "she + 身份(状态)→ Was。" },
|
||||||
|
{ q: "There ___ a supermarket here in 2010.", options: ["were", "is", "was"], answer: 2, explain: "a supermarket 单数 → was。" },
|
||||||
|
{ q: "How ___ the food? — It ___ delicious.", options: ["was / was", "did / was", "were / were"], answer: 0, explain: "food 与 it 都是单数状态 → was。" },
|
||||||
|
{ q: "___ you tired after the game? — No, I ___ .", options: ["Was / weren’t", "Were / wasn’t", "Did / didn’t"], answer: 1, explain: "you → Were;短答语 I wasn’t。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "The past continuous",
|
||||||
|
goal: "用 was/were + -ing 描述过去某一刻“正在发生”的动作。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Forming the past continuous",
|
||||||
|
zh: "过去进行时 = was / were + 动词-ing。",
|
||||||
|
body: "The past continuous is made with was or were plus the -ing form of the verb: I was reading, they were playing. The form of be depends on the subject, just like in the last lesson. This tense paints a picture of an action already in progress at a past moment. We do not see its start or its end; we jump into the middle of the scene, as if we are watching a video paused at that moment.",
|
||||||
|
structure: {
|
||||||
|
cols: ["subject", "be", "verb-ing"],
|
||||||
|
rows: [
|
||||||
|
["I / he / she / it", "was", "sleeping"],
|
||||||
|
["you / we / they", "were", "talking"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["At seven this morning I was still sleeping.", "The children were laughing loudly."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "An action in progress at a past time",
|
||||||
|
zh: "表示过去某一时刻动作正在进行中。",
|
||||||
|
body: "Use the past continuous to say what was happening at a particular past moment. At eight last night, I was doing my homework — at eight I was already in the middle of it, and I finished later. We often fix the time with at that moment, at ten o’clock, all evening, this time yesterday. The answer to the question What were you doing at …? is nearly always in the past continuous.",
|
||||||
|
examples: ["What were you doing at nine? — I was taking a shower.", "It was snowing all day yesterday."],
|
||||||
|
note: "At eight I was doing homework(强调进行中)与 At eight I did homework(当成完成的事)视角不同。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "A long action interrupted by a short one",
|
||||||
|
zh: "长动作用进行时,突然发生的短动作用一般过去时,用 when / while 连接。",
|
||||||
|
body: "Stories often mix the past continuous with the past simple. The continuous sets the background scene; the simple reports the short event that interrupts it. We join the two parts with when or while. While I was walking to school, I saw an old friend. I was cooking when the phone rang. A useful pattern: while is normally followed by the longer continuous part, and when is followed by the short, sudden event.",
|
||||||
|
examples: ["While we were having dinner, the lights went out.", "She was running when she fell."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Past simple vs past continuous",
|
||||||
|
zh: "一般过去时看“完成”,过去进行时看“进行中”;状态动词不用进行时。",
|
||||||
|
body: "The past simple presents an action as a complete event: I walked to school. The past continuous presents it as unfinished, in progress: I was walking to school. Some verbs describe states rather than actions: like, want, know, believe, need. We usually do not put these in the continuous: say I wanted a drink, not I was wanting a drink. When in doubt, ask yourself whether you could actually watch the action happening.",
|
||||||
|
examples: ["I knew the answer. (not: I was knowing)", "We were having fun when Mum called."],
|
||||||
|
note: "状态动词(know, like, want, believe)通常没有 -ing 形式。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "At ten last night, she ___ a book.", options: ["read", "was reading", "reads"], answer: 1, explain: "具体时刻 + 正在进行 → was reading。" },
|
||||||
|
{ q: "While I ___, someone knocked.", options: ["slept", "was sleeping", "sleep"], answer: 1, explain: "while 后接进行的长动作:was sleeping。" },
|
||||||
|
{ q: "They ___ football when it started to rain.", options: ["played", "are playing", "were playing"], answer: 2, explain: "被雨打断的背景动作 → were playing。" },
|
||||||
|
{ q: "I ___ the answer. (know)", options: ["was knowing", "knew", "knows"], answer: 1, explain: "know 是状态动词,不用进行时,用 knew。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "This time yesterday we ___ on the beach.", options: ["were sitting", "sit", "are sitting"], answer: 0, explain: "this time yesterday → 过去进行时 were sitting。" },
|
||||||
|
{ q: "She was singing ___ the teacher came in.", options: ["while", "if", "when"], answer: 2, explain: "when 后接突然发生的短动作。" },
|
||||||
|
{ q: "___ you sleeping at midnight?", options: ["Was", "Were", "Did"], answer: 1, explain: "you + 进行时疑问 → Were you sleeping?" },
|
||||||
|
{ q: "While Dad ___, the baby cried.", options: ["cooked", "was cooking", "cooks"], answer: 1, explain: "while 引导的背景长动作 → was cooking。" },
|
||||||
|
{ q: "We ___ TV at eight last night.", options: ["watched", "watch", "were watching"], answer: 2, explain: "at eight 时正在进行 → were watching。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "used to (past habits, now finished)",
|
||||||
|
goal: "用 used to 表达“过去常常、现在不再”的习惯或状态。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Habits that have ended",
|
||||||
|
zh: "used to 表示过去持续一段时间、现在已不成立的习惯或状态。",
|
||||||
|
body: "We use used to plus the base verb to talk about habits or states that were true for a period in the past but are not true now. I used to live in a small village — now I live in a city. She used to have long hair — now it is short. The form carries a built-in contrast with today. That built-in contrast is exactly what makes it more useful than the plain past simple, which just reports an event.",
|
||||||
|
examples: ["Dad used to smoke, but he stopped.", "I used to be afraid of the dark."],
|
||||||
|
note: "used to 自带“今昔对比”,句子里不必再写时间词。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The form of used to",
|
||||||
|
zh: "used to + 动词原形,所有人称都一样;它只用于过去。",
|
||||||
|
body: "The form is easy: used to plus the base form of the verb. It is the same for every subject: I used to, she used to, they used to. The s is pronounced /s/, and the whole phrase sounds like one word, “yoosta”. Because the meaning is already past, used to never appears in the present. There is no “I use to play”. For present habits we simply use the present simple: I play football every Sunday.",
|
||||||
|
structure: {
|
||||||
|
cols: ["sentence type", "form", "example"],
|
||||||
|
rows: [
|
||||||
|
["positive", "used to + base", "He used to cycle to school."],
|
||||||
|
["negative", "didn’t use to + base", "He didn’t use to like milk."],
|
||||||
|
["question", "Did … use to + base", "Did you use to live here?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["We used to meet every Saturday."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Negatives and questions: watch the spelling",
|
||||||
|
zh: "否定与疑问中写成 use to(没有 -d),因为 did 已扛起过去意义。",
|
||||||
|
body: "In negatives and questions the helper did takes the past meaning, so used to drops its -d and becomes use to. Write it carefully: She didn’t use to get up early. Did you use to play the piano? This tiny spelling change trips up almost everyone, even in exams. A friendly tip: if did or didn’t is already in the sentence, write use; if not, write used. Say the sentences aloud and your ear will soon agree.",
|
||||||
|
examples: ["I didn’t use to eat vegetables, but now I love them.", "Did she use to wear glasses?"],
|
||||||
|
note: "写作中 didn’t used to 是常见拼写错误,考试标准写法是 didn’t use to。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "used to vs the past simple",
|
||||||
|
zh: "过去时只陈述事实,used to 强调“过去如此、现在不”。",
|
||||||
|
body: "The past simple states facts about the past; used to stresses the contrast between then and now. Compare: I lived in Hainan for two years (just a fact) and I used to live in Hainan (but not now). For single events that happened once, use the past simple — we do not say I used to break my arm. A quick test: ask “is it still true now?”. If it might still be true, keep the simple past.",
|
||||||
|
examples: ["I went to Beijing once. (single event, no used to)", "She used to call me every night. (habit, now stopped)"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I ___ to collect stamps when I was little.", options: ["use", "used", "uses"], answer: 1, explain: "肯定句用 used to。" },
|
||||||
|
{ q: "She didn’t ___ to like tea.", options: ["used", "use", "using"], answer: 1, explain: "didn’t 后写 use to。" },
|
||||||
|
{ q: "Did you ___ to walk to school?", options: ["used", "uses", "use"], answer: 2, explain: "Did 提问写 use to。" },
|
||||||
|
{ q: "My grandpa ___ get up at five every day.", options: ["is used to", "used to", "use to"], answer: 1, explain: "过去的习惯 → used to。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "There ___ to be a river here.", options: ["used", "use", "uses"], answer: 0, explain: "肯定句:There used to be。" },
|
||||||
|
{ q: "He ___ to play games every night, but now he studies.", options: ["use", "is using", "used"], answer: 2, explain: "过去习惯现在不再 → used to。" },
|
||||||
|
{ q: "We didn’t ___ to have a car.", options: ["used", "use", "using"], answer: 1, explain: "didn’t 后写 use to。" },
|
||||||
|
{ q: "___ your sister ___ to cry a lot?", options: ["Did / use", "Does / use", "Did / used"], answer: 0, explain: "Did … use to …?" },
|
||||||
|
{ q: "选出正确的一句:", options: ["I used to break my leg.", "I use to live here.", "I broke my leg once."], answer: 2, explain: "一次性动作用一般过去时;used to 无现在式。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "Comparative adjectives (-er / more)",
|
||||||
|
goal: "用 -er 或 more 构成比较级,加 than 比较两个人或物。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Comparing two things",
|
||||||
|
zh: "比较两者时,形容词变比较级,后面常接 than。",
|
||||||
|
body: "When we compare two people or things, we change the adjective into its comparative form and usually add than after it. My bag is heavier than yours. Summer is longer than winter. The comparative answers an implied question: which of the two has more of this quality? In everyday speech than can introduce a clause or a pronoun: She is older than me (informal) or older than I am (more formal).",
|
||||||
|
examples: ["This box is bigger than that one.", "Running is more tiring than walking."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "-er for short adjectives",
|
||||||
|
zh: "单音节形容词加 -er,拼写规则与复数类似。",
|
||||||
|
body: "One-syllable adjectives add -er: tall → taller, fast → faster, old → older. Spelling rules: an adjective ending in -e just adds -r: nice → nicer. A short adjective ending in one vowel plus one consonant doubles the final letter: big → bigger, hot → hotter. A consonant plus -y changes y to i and adds -er: happy → happier, easy → easier. Two-syllable adjectives ending in -y follow the same rule: funny → funnier.",
|
||||||
|
structure: {
|
||||||
|
cols: ["adjective type", "rule", "example"],
|
||||||
|
rows: [
|
||||||
|
["most short words", "+ -er", "tall → taller"],
|
||||||
|
["ending in -e", "+ -r", "nice → nicer"],
|
||||||
|
["short vowel + consonant", "double + -er", "big → bigger"],
|
||||||
|
["consonant + y", "y → i + -er", "happy → happier"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Today is colder than yesterday.", "Her hair is longer than mine."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "more for long adjectives",
|
||||||
|
zh: "多音节形容词在前面加 more,不加 -er。",
|
||||||
|
body: "Adjectives with two or more syllables, except those ending in -y, do not take -er. Instead we put more in front: expensive → more expensive, beautiful → more beautiful, interesting → more interesting. The rule keeps long words easy to say; nobody wants to pronounce “beautifuller”. Some two-syllable adjectives allow both forms, but the safe path is this: one syllable takes -er, three or more syllables take more, and -y words take -ier.",
|
||||||
|
examples: ["This book is more interesting than that one.", "Health is more important than money."],
|
||||||
|
note: "不要两套叠加:more better / more taller 都是错的。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Irregular comparatives",
|
||||||
|
zh: "good → better、bad → worse、far → farther/further,必须死记。",
|
||||||
|
body: "A few everyday adjectives have irregular comparatives that you must simply memorise: good → better, bad → worse, far → farther or further. They follow no spelling rule. In the sentence, than follows the comparative and introduces the second item: The second film is better than the first. If you compare one member with its whole group, add any other: He is taller than any other boy in his class.",
|
||||||
|
structure: {
|
||||||
|
cols: ["adjective", "comparative", "example"],
|
||||||
|
rows: [
|
||||||
|
["good", "better", "Your idea is better than mine."],
|
||||||
|
["bad", "worse", "The weather got worse."],
|
||||||
|
["far", "farther / further", "My school is farther than yours."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I feel worse than I did this morning."],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "This road is ___ than that one.", options: ["more long", "long", "longer"], answer: 2, explain: "long 单音节加 -er:longer。" },
|
||||||
|
{ q: "The story is ___ than the film.", options: ["more interesting", "interestinger", "most interesting"], answer: 0, explain: "多音节形容词用 more。" },
|
||||||
|
{ q: "My bag is ___ (heavy) than yours.", options: ["more heavy", "heavier", "heavyer"], answer: 1, explain: "辅音 + y 变 ier:heavier。" },
|
||||||
|
{ q: "This restaurant is ___ than the one near my home.", options: ["gooder", "more good", "better"], answer: 2, explain: "good 的比较级是不规则变化 better。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "Elephants are ___ than horses.", options: ["bigger", "biger", "more big"], answer: 0, explain: "big 双写 g 加 -er:bigger。" },
|
||||||
|
{ q: "Maths is ___ than music for me.", options: ["difficulter", "most difficult", "more difficult"], answer: 2, explain: "多音节形容词用 more difficult。" },
|
||||||
|
{ q: "Today I feel ___ than yesterday.", options: ["best", "better", "good"], answer: 1, explain: "good → better。" },
|
||||||
|
{ q: "Her dress is ___ than mine.", options: ["nicer", "more nice", "nicest"], answer: 0, explain: "nice 以 e 结尾加 -r:nicer。" },
|
||||||
|
{ q: "It’s ___ to take the bus than to walk.", options: ["more fast", "faster", "fast"], answer: 1, explain: "fast 单音节加 -er:faster。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "weekly",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "第 4 周测验",
|
||||||
|
intro: "本周你学了一般过去时(不规则动词、否定疑问)、was/were 与 there was/were、过去进行时、used to 和比较级,下面 10 题综合检测,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "She ___ her keys yesterday.", options: ["losed", "lost", "lose"], answer: 1, explain: "lose 的过去式是 lost。" },
|
||||||
|
{ q: "We didn’t ___ the film.", options: ["like", "liked", "liking"], answer: 0, explain: "didn’t 后用动词原形 like。" },
|
||||||
|
{ q: "___ you at the party last night?", options: ["Did", "Was", "Were"], answer: 2, explain: "you + 地点状态 → Were。" },
|
||||||
|
{ q: "There ___ many trees here long ago.", options: ["were", "was", "is"], answer: 0, explain: "trees 复数 → were。" },
|
||||||
|
{ q: "At seven this morning I ___ breakfast.", options: ["had", "have", "was having"], answer: 2, explain: "具体时刻正在进行 → was having。" },
|
||||||
|
{ q: "While she was reading, the phone ___ .", options: ["was ringing", "rang", "rings"], answer: 1, explain: "被打断的短动作用一般过去时 rang。" },
|
||||||
|
{ q: "My dad ___ to drive to work, but now he cycles.", options: ["use", "used", "uses"], answer: 1, explain: "过去习惯现在不再 → used to。" },
|
||||||
|
{ q: "This question is ___ than that one.", options: ["more easy", "easy", "easier"], answer: 2, explain: "easy 辅音 + y 变 ier:easier。" },
|
||||||
|
{ q: "The weather today is ___ than yesterday.", options: ["worse", "badder", "more bad"], answer: 0, explain: "bad 的比较级是 worse。" },
|
||||||
|
{ q: "___ did she say at the meeting?", options: ["Where", "What", "Who"], answer: 1, explain: "询问说的内容用 What。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,341 @@
|
|||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 第 5 周:A2 进阶 —— 最高级、as ... as 与比较级加强、enough 与 too、
|
||||||
|
// 将来时 be going to 与 will、will 与 going to 的取舍及用现在时表将来。
|
||||||
|
// 全部讲解、例句、练习、测验均为原创,仅使用语法主题名称。
|
||||||
|
|
||||||
|
export const week05: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "Superlative adjectives (-est / most)",
|
||||||
|
goal: "用 -est 或 most 构成最高级,加 the 表示“最……”。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Comparing three or more",
|
||||||
|
zh: "拿一个跟整组比,用最高级,前面几乎总要加 the。",
|
||||||
|
body: "When we compare one thing with a whole group, we use the superlative: the tallest, the most expensive. The superlative means “more than all the others”. We almost always put the in front of it, and we often name the group with in or of: the tallest boy in our class, the best day of my life. Without a group, the sentence feels unfinished: Which is the longest river? — longest among what?",
|
||||||
|
examples: ["Mount Everest is the highest mountain in the world.", "This is the funniest joke I know."],
|
||||||
|
note: "最高级前别忘了 the:the tallest,而不是 tallest。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "-est for short adjectives",
|
||||||
|
zh: "短形容词加 -est,拼写规则与比较级完全一致。",
|
||||||
|
body: "Short adjectives add -est, following exactly the same spelling rules as -er. tall → tallest; an adjective ending in -e adds just -st: nice → nicest; a short adjective ending in one vowel plus one consonant doubles the final letter: big → biggest, hot → hottest; a consonant plus -y changes to i: happy → happiest, busy → busiest. Two-syllable adjectives ending in -y take -iest: funny → funniest. Everything you learned for comparatives carries straight over.",
|
||||||
|
structure: {
|
||||||
|
cols: ["adjective type", "rule", "example"],
|
||||||
|
rows: [
|
||||||
|
["most short words", "+ -est", "fast → fastest"],
|
||||||
|
["ending in -e", "+ -st", "large → largest"],
|
||||||
|
["short vowel + consonant", "double + -est", "thin → thinnest"],
|
||||||
|
["consonant + y", "y → i + -est", "easy → easiest"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["She is the youngest player in the team.", "August is the hottest month here."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "the most for long adjectives",
|
||||||
|
zh: "多音节形容词用 the most,词本身不变。",
|
||||||
|
body: "Long adjectives form the superlative with the most instead of an ending: the most beautiful, the most dangerous, the most exciting. The adjective itself does not change. As with comparatives, -y adjectives are the exception and take -iest: the friendliest, the noisiest. The choice mirrors the comparative exactly: if you said more interesting, say the most interesting; if you said taller, say the tallest. Never mix the two systems inside one word.",
|
||||||
|
examples: ["That was the most exciting match of the year.", "He is the most careful driver I know."],
|
||||||
|
note: "the most biggest 是错的;the most 不能和 -est 叠用。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Irregular superlatives",
|
||||||
|
zh: "good → the best,bad → the worst,far → the farthest/furthest。",
|
||||||
|
body: "The three irregular adjectives from comparatives reappear here: good → the best, bad → the worst, far → the farthest or the furthest. They are extremely common, so they are worth learning as fixed chunks. Notice that best and worst carry no adjective ending at all — they must simply be memorised. We use them for everything from food to films to exam results: This is the best cake I have ever eaten.",
|
||||||
|
structure: {
|
||||||
|
cols: ["adjective", "comparative", "superlative"],
|
||||||
|
rows: [
|
||||||
|
["good", "better", "the best"],
|
||||||
|
["bad", "worse", "the worst"],
|
||||||
|
["far", "farther", "the farthest"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Yesterday was the worst day of the week.", "Who is the best singer in your family?"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "Tom is the ___ player in the team.", options: ["tall", "taller", "tallest"], answer: 2, explain: "与全队比,用最高级 tallest。" },
|
||||||
|
{ q: "This is ___ book I have ever read.", options: ["the most interesting", "the interestinger", "the interestingest"], answer: 0, explain: "多音节形容词用 the most interesting。" },
|
||||||
|
{ q: "She got the ___ mark in the exam.", options: ["baddest", "worst", "more bad"], answer: 1, explain: "bad 的最高级是 the worst。" },
|
||||||
|
{ q: "It was the ___ day of the year.", options: ["hotest", "most hot", "hottest"], answer: 2, explain: "hot 双写 t 加 -est:hottest。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "That is ___ film of the year.", options: ["the goodest", "the best", "the most good"], answer: 1, explain: "good 的最高级是 the best。" },
|
||||||
|
{ q: "My grandma tells the ___ stories.", options: ["most funny", "funnyest", "funniest"], answer: 2, explain: "辅音 + y 变 iest:funniest。" },
|
||||||
|
{ q: "This is ___ question in the book.", options: ["the most difficult", "the difficulter", "the difficultest"], answer: 0, explain: "多音节形容词用 the most difficult。" },
|
||||||
|
{ q: "Who runs ___ in your class?", options: ["the most fast", "the faster", "the fastest"], answer: 2, explain: "fast 加 -est:the fastest。" },
|
||||||
|
{ q: "It was the ___ holiday ever.", options: ["most bad", "worst", "badder"], answer: 1, explain: "bad 的最高级是 the worst。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "(not) as … as and strengthening comparatives",
|
||||||
|
goal: "用 as … as 表示“一样”,用 much / a bit 等说明差距大小。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "as … as: the same",
|
||||||
|
zh: "as + 形容词原级 + as,表示两者“一样……”。",
|
||||||
|
body: "To say that two things are equal in some quality, we use as plus adjective plus as. Tom is as tall as his father. My phone is as old as yours. The adjective stays in its plain form between the two as words — no -er, no more. This structure is the friendly opposite of the comparative: the comparative says one thing has more, while as … as says neither has more; the two are level.",
|
||||||
|
examples: ["She sings as well as a pop star.", "This task is as easy as that one."],
|
||||||
|
note: "修饰动词唱歌要用副词 well:as well as,不说 as good as。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "not as … as: less than",
|
||||||
|
zh: "not as … as 表示前者“不如”后者,语气比比较级委婉。",
|
||||||
|
body: "The negative form not as … as says the first thing has less of the quality: This film is not as good as the book — the book wins. It is a softer, very common way to make a comparison; in meaning it equals a comparative sentence, but the order is reversed: not as cheap as means the same as more expensive than. In older writing people say not so … as, though as … as is more usual today.",
|
||||||
|
examples: ["Today is not as cold as yesterday.", "My bag isn’t as heavy as yours."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Big differences: much / a lot / far",
|
||||||
|
zh: "差距大时,在比较级前加 much / a lot / far。",
|
||||||
|
body: "A comparative alone only says that one thing has more. To show that the difference is large, we put much, a lot, or far in front of the comparative: much bigger, a lot more expensive, far better. These words work like a volume knob turned up high. We use them when the gap is obvious: The new phone is much faster than my old one. They never stand in front of a plain adjective: much better, never much good.",
|
||||||
|
examples: ["This box is a lot heavier than that one.", "She is far more confident than last year."],
|
||||||
|
note: "much / a lot / far 后面必须接比较级:much better ✓,much good ✗。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Small differences: a bit / a little / slightly",
|
||||||
|
zh: "差距小时,加 a bit / a little / slightly。",
|
||||||
|
body: "For small differences we turn the knob the other way with a bit, a little, or slightly: a bit colder, a little more expensive, slightly faster. These are extremely useful for being polite and precise. Could you speak a little more slowly? This road is a bit longer, but it is prettier. The three words mean almost the same; a bit is informal and common in speech, while slightly sounds a touch more careful.",
|
||||||
|
examples: ["Can we leave a bit earlier tomorrow?", "The red shirt is slightly cheaper than the blue one."],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She is as ___ as her mother.", options: ["taller", "tall", "tallest"], answer: 1, explain: "as … as 中间用形容词原级。" },
|
||||||
|
{ q: "This shop is not as ___ as the other one.", options: ["cheaper", "cheapest", "cheap"], answer: 2, explain: "not as … as 也用原级 cheap。" },
|
||||||
|
{ q: "The test was ___ harder than I expected.", options: ["very", "much", "more"], answer: 1, explain: "加强比较级用 much:much harder。" },
|
||||||
|
{ q: "Could you drive a bit ___?", options: ["slow", "slower", "slowest"], answer: 1, explain: "a bit + 比较级:a bit slower。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "My room is ___ as yours.", options: ["as bigger", "so bigger", "as big"], answer: 2, explain: "as + 原级 + as。" },
|
||||||
|
{ q: "The film wasn’t ___ the book.", options: ["as better as", "so good than", "as good as"], answer: 2, explain: "否定比较:not as good as。" },
|
||||||
|
{ q: "The new bridge is ___ longer than the old one.", options: ["very", "much", "more"], answer: 1, explain: "much 修饰比较级 longer。" },
|
||||||
|
{ q: "Today feels ___ colder than yesterday.", options: ["many", "very", "a bit"], answer: 2, explain: "小差距用 a bit + 比较级。" },
|
||||||
|
{ q: "She runs ___ me.", options: ["as faster as", "as fast as", "so fast than"], answer: 1, explain: "as + 原级(fast)+ as。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "(not) enough and too",
|
||||||
|
goal: "用 enough 表示“足够”、too 表示“太……(不好)”,掌握词序。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "adjective + enough",
|
||||||
|
zh: "enough 放在形容词后面,表示“足够……”。",
|
||||||
|
body: "We use enough after an adjective to mean “as much as is needed”. She is old enough to travel alone. The soup is hot enough — we can eat. Notice the order carefully: enough comes after the adjective, never before. We do not say “enough old”. In a negative sentence, not plus adjective plus enough says something is below the level needed: He is not tall enough to reach the shelf.",
|
||||||
|
examples: ["Is the tea sweet enough for you?", "These shoes aren’t big enough for me."],
|
||||||
|
note: "enough 放形容词之后:old enough ✓;enough old ✗。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "enough + noun",
|
||||||
|
zh: "enough 放在名词前面:enough time、enough money。",
|
||||||
|
body: "With a noun the order flips: enough comes before the noun. Do we have enough time? There aren’t enough chairs for everyone. So the rule is simple: after an adjective (warm enough), before a noun (enough money). This one switch is the reason enough feels tricky, but once you see the pattern it is completely predictable. When enough stands alone, it works like a pronoun: I’ve had enough, thanks.",
|
||||||
|
examples: ["We don’t have enough food for ten people.", "Did you get enough sleep last night?"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "too: more than is good",
|
||||||
|
zh: "too 放在形容词前,表示“太……”,含负面意味。",
|
||||||
|
body: "Too also comes before an adjective, but its meaning is negative: more than is wanted or good. The coat is too expensive — I won’t buy it. You are driving too fast! Don’t confuse too with very. Very simply adds strength and can be good or bad: very good, very fast. Too always means a problem, a limit crossed: too hot to drink, too tired to think. If there is no problem, use very instead.",
|
||||||
|
examples: ["This box is too heavy for me to lift.", "He talked too quietly, so I missed half of it."],
|
||||||
|
note: "very = 很(中性);too = 太(超出限度,通常是问题)。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "enough to / too … to",
|
||||||
|
zh: "enough to 表示“够得上能做”,too … to 表示“太……而不能”。",
|
||||||
|
body: "Both words often join the adjective to an action with to plus verb. adjective plus enough plus to: She is strong enough to carry the bag. too plus adjective plus to: The question was too hard to answer. The two sentences are near opposites: enough to means it can be done, too … to means it cannot. For a person we can add for: It is too cold for the baby to go outside.",
|
||||||
|
examples: ["He is old enough to ride to school alone.", "The box was too big to fit in the car."],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She is clever ___ to solve it.", options: ["too", "enough", "very"], answer: 1, explain: "形容词后接 enough:clever enough。" },
|
||||||
|
{ q: "We don’t have ___ chairs.", options: ["too", "enough", "very"], answer: 1, explain: "名词前用 enough:enough chairs。" },
|
||||||
|
{ q: "The music is ___ loud — turn it down!", options: ["too", "very", "enough"], answer: 0, explain: "超出限度、要关小 → too loud。" },
|
||||||
|
{ q: "He isn’t tall ___ to reach the apple.", options: ["enough", "too", "very"], answer: 0, explain: "形容词后用 enough:tall enough。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "This T-shirt is ___ small for me.", options: ["too", "enough", "many"], answer: 0, explain: "太小(有问题)→ too small。" },
|
||||||
|
{ q: "Have you got ___ money for the ticket?", options: ["too", "enough", "very"], answer: 1, explain: "名词 money 前用 enough。" },
|
||||||
|
{ q: "The water isn’t warm ___ to swim in.", options: ["too", "enough", "very"], answer: 1, explain: "形容词 warm 后用 enough。" },
|
||||||
|
{ q: "It’s ___ cold to eat ice cream today.", options: ["enough", "too", "very much"], answer: 1, explain: "too cold to …:太冷而不能。" },
|
||||||
|
{ q: "She speaks ___ for me to understand.", options: ["fast enough", "enough fast", "too fast"], answer: 2, explain: "太快听不懂 → too fast。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "The future: be going to",
|
||||||
|
goal: "用 be going to 表达事先的打算和有迹象的预测。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Plans and intentions",
|
||||||
|
zh: "说话前就已决定的打算,用 be going to。",
|
||||||
|
body: "We use be going to plus the base verb to talk about the future. Its first job is plans and intentions: things you have already decided to do. I’m going to visit my grandparents this weekend — the decision was made before now. This is the big difference from will, which we meet next lesson. If you have a plan in your pocket when you start speaking, going to is usually the right choice.",
|
||||||
|
examples: ["We’re going to have a picnic on Saturday.", "She’s going to learn the guitar this summer."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The form of be going to",
|
||||||
|
zh: "am / is / are + going to + 动词原形。",
|
||||||
|
body: "The form has three parts: the right form of be (am, is, are), then going to, then the base verb. Match be to the subject, exactly as in the present tense. In speech and informal writing we usually contract: I’m going to, she’s going to, they’re going to. Native speakers often squeeze going to into “gonna” in very casual talk, but in your homework and in exams, always write the full form.",
|
||||||
|
structure: {
|
||||||
|
cols: ["subject", "be", "example"],
|
||||||
|
rows: [
|
||||||
|
["I", "am", "I’m going to tidy my room."],
|
||||||
|
["he / she / it", "is", "It’s going to be a long day."],
|
||||||
|
["you / we / they", "are", "We’re going to win!"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Dad is going to cook dinner tonight."],
|
||||||
|
note: "写作里写 going to;gonna 只出现在非常口语的场合。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Negatives and questions",
|
||||||
|
zh: "否定在 be 后加 not;疑问把 be 提到句首。",
|
||||||
|
body: "To make a negative, add not after be: I’m not going to wait any longer. They aren’t going to come. The main verb stays in its base form after to. For questions, move be to the front: Are you going to join the club? Is she going to sing? Short answers repeat be: Yes, I am. / No, they aren’t. Wh- questions add the question word at the front: What are you going to do?",
|
||||||
|
examples: ["I’m not going to tell you — it’s a secret!", "Where are you going to sit?"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Predictions with present evidence",
|
||||||
|
zh: "眼前有明显迹象的预测,也用 going to。",
|
||||||
|
body: "The second job of going to is predictions based on something we can see or feel right now. Look at those black clouds — it’s going to rain. Watch out! You’re going to fall! The evidence in the present points straight to the future, so the future feels certain and close. This is why going to fits warnings so well. If the prediction comes from evidence in front of your eyes, choose going to rather than will.",
|
||||||
|
examples: ["The score is 3–0 with one minute left. We’re going to win.", "Mind that step — you’re going to trip."],
|
||||||
|
note: "有眼前证据的预测 → going to;凭想法的猜测 → will(下一课)。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I ___ going to call her tonight.", options: ["am", "is", "are"], answer: 0, explain: "I 配 am。" },
|
||||||
|
{ q: "Look out! The cup ___ going to fall!", options: ["are", "is", "am"], answer: 1, explain: "the cup 单数 → is。" },
|
||||||
|
{ q: "___ they going to move next month?", options: ["Is", "Are", "Am"], answer: 1, explain: "they → Are。" },
|
||||||
|
{ q: "She isn’t going to ___ the race.", options: ["join", "joins", "joining"], answer: 0, explain: "to 后用动词原形 join。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "We ___ going to paint the kitchen yellow.", options: ["is", "are", "am"], answer: 1, explain: "we → are。" },
|
||||||
|
{ q: "Look at the traffic — we ___ going to be late.", options: ["are", "is", "be"], answer: 0, explain: "we → are going to be。" },
|
||||||
|
{ q: "___ you going to help me or not?", options: ["Is", "Are", "Do"], answer: 1, explain: "you 疑问 → Are you going to …?" },
|
||||||
|
{ q: "I’m not going to ___ up early tomorrow.", options: ["gets", "get", "getting"], answer: 1, explain: "to 后用原形 get。" },
|
||||||
|
{ q: "The clouds are gone; it ___ going to be a nice day.", options: ["are", "were", "is"], answer: 2, explain: "it → is going to be。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "The future: will (predictions, promises, instant decisions)",
|
||||||
|
goal: "用 will 表达预测、承诺、提议和说话瞬间的决定。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Predictions: what you think will happen",
|
||||||
|
zh: "凭看法而非眼前证据的预测,用 will。",
|
||||||
|
body: "Will plus the base verb is our second future form. Its first job is predictions based on opinion rather than visible evidence: I think it will rain tomorrow. One day, people will live on Mars. We often signal opinion with I think, I’m sure, I expect, probably, perhaps. There are no dark clouds to point at — the prediction lives in your head. That is exactly where will beats going to.",
|
||||||
|
examples: ["I’m sure you will love this song.", "She’ll probably be late, as usual."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Promises, offers, and instant decisions",
|
||||||
|
zh: "承诺、提议、说话时才做的决定,用 will。",
|
||||||
|
body: "The second job of will is reacting in the moment. Someone offers, promises, or decides while speaking — there was no plan before. I’ll help you carry those bags (offer). I won’t tell anyone your secret (promise). The phone is ringing — I’ll get it (instant decision). This is why the menu moment uses will: I’ll have the noodles, please. If the decision is born at the moment of speaking, will is the natural choice.",
|
||||||
|
examples: ["Don’t worry, I’ll water your plants every day.", "It’s cold in here. I’ll close the window."],
|
||||||
|
note: "事先的计划 → going to;说话瞬间的决定 → will。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The form of will",
|
||||||
|
zh: "will 不变形,后接动词原形;否定缩写 won’t。",
|
||||||
|
body: "Will is wonderfully simple: it never changes form. Every subject takes the same word: I will, she will, they will. The main verb stays in its base form with no -s: she will go, never she will goes. In speech and informal writing we contract with ’ll: I’ll, you’ll, he’ll, it’ll, we’ll, they’ll. The negative is will not, almost always written and said as won’t. Questions put will first: Will you come?",
|
||||||
|
structure: {
|
||||||
|
cols: ["sentence type", "form", "example"],
|
||||||
|
rows: [
|
||||||
|
["positive", "will + base", "It will snow tonight."],
|
||||||
|
["negative", "won’t + base", "They won’t mind."],
|
||||||
|
["question", "Will … + base", "Will you wait for me?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I’ll always be your friend."],
|
||||||
|
note: "will 后接动词原形:she will goes ✗;won’t 是 will not 的缩写。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "How sure are you?",
|
||||||
|
zh: "用 I’m sure / probably / maybe 表达不同的把握程度。",
|
||||||
|
body: "We can show how confident a prediction is. I’m sure and definitely sit close to certain: I’m sure he’ll pass. probably and I think sit in the middle: It’ll probably snow. Perhaps and maybe sit near guessing: Maybe they’ll move next year. In negatives, probably usually comes before won’t: He probably won’t come. These little words make your English sound natural and honest — real people are rarely one hundred percent sure about tomorrow.",
|
||||||
|
examples: ["I’ll probably finish the book tonight.", "Maybe Dad will take us swimming on Sunday."],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I think it ___ snow tomorrow.", options: ["will", "is going", "going to"], answer: 0, explain: "凭看法预测用 will。" },
|
||||||
|
{ q: "The bag looks heavy. I ___ carry it for you.", options: ["am going to", "will", "am"], answer: 1, explain: "当场主动提议 → will。" },
|
||||||
|
{ q: "She ___ tell anyone — it’s a promise.", options: ["won’t", "doesn’t", "isn’t"], answer: 0, explain: "承诺用 won’t(will not)。" },
|
||||||
|
{ q: "___ you help me, please?", options: ["Are", "Do", "Will"], answer: 2, explain: "请求用 Will you …?" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "I’m sure everything ___ be fine.", options: ["will", "is going", "goes"], answer: 0, explain: "I’m sure + will 表预测。" },
|
||||||
|
{ q: "A: We’ve run out of milk. B: Really? I ___ get some.", options: ["am going to", "get", "will"], answer: 2, explain: "刚听说、当场决定 → will。" },
|
||||||
|
{ q: "He ___ come to the party; he’s busy.", options: ["won’t probably", "probably won’t", "not will"], answer: 1, explain: "probably 放在 won’t 之前。" },
|
||||||
|
{ q: "Don’t worry — I ___ say a word.", options: ["don’t", "won’t", "am not"], answer: 1, explain: "承诺保密 → won’t。" },
|
||||||
|
{ q: "Perhaps she ___ us later.", options: ["will call", "calls", "calling"], answer: 0, explain: "perhaps + will 表猜测。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "will vs going to; the present tenses for the future",
|
||||||
|
goal: "区分 will 与 going to,并学会用现在进行时和一般现在时表将来。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Plan or instant decision?",
|
||||||
|
zh: "事先打算用 going to,临时决定用 will。",
|
||||||
|
body: "The classic pair: I’m going to study medicine (decided long ago — a plan) and A: The phone’s ringing. B: I’ll get it (decided right now). Use going to when the intention existed before this conversation; use will when the decision is born in the moment. A test that helps: if you could honestly add “I already planned it”, use going to. If you could add “OK, I’ve just decided”, use will.",
|
||||||
|
examples: ["We’re going to fly to Xi’an in October — I booked the tickets.", "This soup is cold. I’ll heat it up."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Predictions: both are possible",
|
||||||
|
zh: "预测两者常可通用:眼前证据偏 going to,个人看法偏 will。",
|
||||||
|
body: "For predictions, will and going to often both work, with a small difference in feel. Evidence you can see now pulls toward going to: Look at the queue — we’re going to wait forever. Opinion with no evidence pulls toward will: I think robots will teach us one day. In many everyday sentences the choice hardly matters, and nobody will misunderstand you. When the evidence is standing right in front of you, going to is the safer pick.",
|
||||||
|
examples: ["She’s been practising for months. She’s going to play brilliantly.", "I hope the bus will come soon."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Present continuous for fixed plans",
|
||||||
|
zh: "时间地点已定的安排,用现在进行时表将来。",
|
||||||
|
body: "There is a third way to talk about the future: the present continuous, the -ing form. We use it for fixed arrangements — plans where a time, place, or other person is already settled. I’m meeting Anna at six. We’re flying to Tokyo on Friday. This sounds even more definite than going to; the diary is written. It works best with personal arrangements involving other people or booked things like tickets and tables.",
|
||||||
|
examples: ["What are you doing this evening?", "He’s seeing the dentist at four tomorrow."],
|
||||||
|
note: "已约好的安排(时间/人确定)→ 现在进行时最自然:I’m meeting Anna at six。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Present simple for timetables",
|
||||||
|
zh: "火车、航班、开学等固定时刻表,用一般现在时表将来。",
|
||||||
|
body: "The last future form looks surprising: the present simple. We use it for fixed schedules run by organisations — trains, buses, films, school terms, TV programmes. The train leaves at 7:15. School starts on the first of September. The timetable exists independently of you and me, so English treats it like a fact. Notice we do not normally say the train will leave at 7:15; the present simple is the standard choice here.",
|
||||||
|
examples: ["What time does the film start?", "The museum closes at five on Sundays."],
|
||||||
|
note: "公共时刻表(车、航班、校历)→ 一般现在时:The bus arrives at nine,不说 will arrive。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "A: I’m thirsty. B: I ___ get you some water.", options: ["will", "am going to", "get"], answer: 0, explain: "当场反应 → will。" },
|
||||||
|
{ q: "We ___ to Hainan next week — here are the tickets.", options: ["are flying", "flew", "fly"], answer: 0, explain: "票已订好的安排 → 现在进行时。" },
|
||||||
|
{ q: "The bus ___ at eight every morning.", options: ["leaves", "will leave", "leaving"], answer: 0, explain: "时刻表 → 一般现在时 leaves。" },
|
||||||
|
{ q: "Look at the sun! It ___ a hot day.", options: ["will", "is going to be", "being"], answer: 1, explain: "眼前证据(大太阳)→ is going to be。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "A: Why are you buying flour? B: I ___ make a cake.", options: ["will", "am going to", "make"], answer: 1, explain: "买面粉说明早有打算 → am going to。" },
|
||||||
|
{ q: "A: These bags are heavy! B: I ___ carry one for you.", options: ["am going to", "carry", "will"], answer: 2, explain: "当场主动帮忙 → will。" },
|
||||||
|
{ q: "Hurry up! The train ___ in ten minutes.", options: ["leaves", "left", "will leaving"], answer: 0, explain: "时刻表 → 一般现在时 leaves。" },
|
||||||
|
{ q: "She’s been training all year. She ___ win the race.", options: ["leaves", "is going to", "left"], answer: 1, explain: "有长期训练作证据 → is going to。" },
|
||||||
|
{ q: "What ___ you ___ this weekend? (already arranged)", options: ["are / doing", "will / doing", "do / doing"], answer: 0, explain: "已定安排用现在进行时:are … doing。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "weekly",
|
||||||
|
cefr: "A2",
|
||||||
|
title: "第 5 周测验",
|
||||||
|
intro: "本周你学了最高级、as … as 与比较级加强、enough 与 too、将来时 going to 与 will,下面 10 题综合检测,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "This is ___ cake I’ve ever tasted.", options: ["the best", "the goodest", "best"], answer: 0, explain: "good 的最高级是 the best,前面要有 the。" },
|
||||||
|
{ q: "He isn’t as ___ as his brother.", options: ["tall", "taller", "tallest"], answer: 0, explain: "not as … as 用形容词原级。" },
|
||||||
|
{ q: "The new phone is ___ faster than mine.", options: ["very", "more", "much"], answer: 2, explain: "加强比较级用 much。" },
|
||||||
|
{ q: "The suitcase is ___ heavy for me to carry.", options: ["too", "enough", "very"], answer: 0, explain: "太重搬不动 → too heavy to carry。" },
|
||||||
|
{ q: "Are you old ___ to travel alone?", options: ["too", "very", "enough"], answer: 2, explain: "形容词后用 enough:old enough。" },
|
||||||
|
{ q: "Look at that tree! It ___ fall.", options: ["will", "is going to", "falls"], answer: 1, explain: "眼前有迹象 → is going to。" },
|
||||||
|
{ q: "A: The doorbell rang. B: I ___ get it.", options: ["am going to", "get", "will"], answer: 2, explain: "当场决定 → will(I’ll get it)。" },
|
||||||
|
{ q: "I’m sure you ___ enjoy the trip.", options: ["will", "are going", "going"], answer: 0, explain: "I’m sure + will 表预测。" },
|
||||||
|
{ q: "The plane ___ at 6:40 tomorrow morning.", options: ["took off", "takes off", "taking off"], answer: 1, explain: "航班时刻表 → 一般现在时 takes off。" },
|
||||||
|
{ q: "I’ve already decided. I ___ tell her the truth tonight.", options: ["will", "tell", "am going to"], answer: 2, explain: "早已决定 → am going to。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,358 @@
|
|||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 第 6 周:B1 —— 现在完成时家族(人生经历、just/already/yet、与一般过去时的对比、
|
||||||
|
// for 与 since、现在完成进行时)以及 must / have to / mustn't(义务与禁止)
|
||||||
|
// 全部讲解、例句、练习、测验均为原创,仅使用语法主题名称,不参考任何书籍正文。
|
||||||
|
|
||||||
|
export const week06: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "The present perfect 1: life experience (Have you ever …?)",
|
||||||
|
goal: "学会用现在完成时 have/has + 过去分词谈论人生经历,会问 Have you ever…?",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Form: have / has + past participle",
|
||||||
|
zh: "现在完成时由 have/has 加动词的过去分词构成。",
|
||||||
|
body: "The present perfect is made with “have” or “has” plus the past participle of the main verb. Use “have” with I, you, we, they; use “has” with he, she, it. Regular past participles end in -ed, like “visited” or “played”. Many common verbs are irregular, so learn their forms bit by bit: see → seen, eat → eaten, ride → ridden, be → been. In speech we nearly always shorten the helper: “I have” → “I’ve”, “she has” → “she’s”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Subject", "helper", "past participle", "Example"],
|
||||||
|
rows: [
|
||||||
|
["I / You / We / They", "have (’ve)", "visited", "I’ve visited Beijing."],
|
||||||
|
["He / She / It", "has (’s)", "eaten", "She’s eaten sushi."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I have visited Beijing twice.", "She has never eaten sushi.", "They have seen that film three times."],
|
||||||
|
note: "过去分词不等于过去式:go → went → gone,do → did → done,不规则形式要单独记。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Talking about life experience",
|
||||||
|
zh: "谈论「这辈子有没有做过某事」,时间不重要,经历本身才重要。",
|
||||||
|
body: "We use the present perfect to talk about the experiences in our whole life up to now. The exact time does not matter — maybe we cannot even remember it. What matters is the experience itself. Sentences like this often include words such as “ever”, “never”, “once”, “twice”, or “many times”. Compare these two: “I ate sushi.” (one finished moment) and “I have eaten sushi.” (at some point in my life).",
|
||||||
|
examples: ["My grandfather has never flown in a plane.", "We have moved house three times.", "I have read this story many times."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Questions with “ever”, answers with “never”",
|
||||||
|
zh: "ever 放在 have 和过去分词之间问经历;never 表示「从未」。",
|
||||||
|
body: "To ask about someone’s life experience, put “ever” between “have” and the past participle: “Have you ever climbed a mountain?” Short answers repeat the helper: “Yes, I have.” / “No, I haven’t.” To say “not at any time in my life”, use “never” in a positive-form sentence: “I have never tried skiing.” Notice that “never” already carries the negative meaning, so we do not add “not”.",
|
||||||
|
examples: ["Have you ever ridden a horse?", "I have never broken a bone.", "Has she ever been on TV?"],
|
||||||
|
note: "“I have never…” 是肯定句式里加 never,不能再写 “I haven’t never…”,那是双重否定。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "gone to and been to",
|
||||||
|
zh: "gone to = 去了还没回;been to = 去过已回来。",
|
||||||
|
body: "“Gone” and “been” look similar but mean different things. “She has gone to the library” means she is there now, or on her way — she has not come back. “She has been to the library” means she went and returned; the trip is finished. With places we have visited somewhere in our life, we use “been to”: “I have been to Xi’an twice.” Only “been to” works for counting visits.",
|
||||||
|
examples: ["Where’s Tom? He’s gone to the shop.", "I’ve been to Shanghai once.", "They’ve gone home — the lights are off."],
|
||||||
|
note: "不能说 “I have gone to Beijing twice.”,数次数只能用 been to。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She has never ___ Thai food.", options: ["try", "tried", "tries"], answer: 1, explain: "has 后用过去分词 tried。" },
|
||||||
|
{ q: "___ you ever ___ a horse?", options: ["Have / ridden", "Has / ridden", "Did / ridden"], answer: 0, explain: "you 用 Have;ever 后接过去分词 ridden。" },
|
||||||
|
{ q: "I ___ been to Guangzhou.", options: ["has", "have", "am"], answer: 1, explain: "I 搭配 have。" },
|
||||||
|
{ q: "Tom isn’t here. He has ___ to the library.", options: ["been", "gone", "go"], answer: 1, explain: "人不在 = 去了没回来,用 gone to。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "They have ___ that film five times.", options: ["see", "seen", "saw"], answer: 1, explain: "have 后接过去分词 seen。" },
|
||||||
|
{ q: "___ she ever ___ skiing?", options: ["Has / tried", "Have / tried", "Did / tried"], answer: 0, explain: "she 用 Has;did 不与过去分词搭配。" },
|
||||||
|
{ q: "My aunt has never ___ coffee.", options: ["drink", "drank", "drunk"], answer: 2, explain: "drink 的过去分词是 drunk。" },
|
||||||
|
{ q: "I have been to Beijing twice, but I have never ___ to Xi’an.", options: ["be", "been", "gone"], answer: 1, explain: "谈去过某地的经历用 been to。" },
|
||||||
|
{ q: "Where’s Lily? — She has ___ the supermarket. She’ll be back in an hour.", options: ["gone to", "been to", "go to"], answer: 0, explain: "她还没回来,用 gone to。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "The present perfect 2: just / already / yet",
|
||||||
|
goal: "掌握 just / already / yet 的意思和在现在完成时中的位置。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "just — a moment ago",
|
||||||
|
zh: "just 表示「刚刚」,放在 have/has 和过去分词中间。",
|
||||||
|
body: "“Just” means a very short time ago — seconds or minutes. It goes between the helper “have/has” and the past participle: “I’ve just finished my homework.” The action is so recent that its result is still fresh: the plate is still warm, the floor is still wet. We normally use “just” in positive sentences. In speaking, the word “just” usually carries the stress of the sentence.",
|
||||||
|
examples: ["I’ve just washed the dishes.", "Don’t touch the wall — I’ve just painted it.", "The bus has just left."],
|
||||||
|
note: "just 的位置是 have + just + 过去分词,不能放到句尾。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "already — sooner than expected",
|
||||||
|
zh: "already 表示「已经」,多用于肯定句,也在中间位置。",
|
||||||
|
body: "“Already” means something happened sooner than expected, or it is simply done by now. It also sits between “have/has” and the past participle: “The train has already left.” We use it mostly in positive sentences and sometimes in surprised questions: “Have you finished already?” Do not use “already” in ordinary negatives. Watch the spelling: it is one word, quite different from “all ready”.",
|
||||||
|
examples: ["We’ve already had lunch.", "She’s already read two books this week.", "Have you done it already?"],
|
||||||
|
note: "already 是一个词;“all ready” 是「都准备好了」,意思完全不同。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "yet — up to now",
|
||||||
|
zh: "yet 表示「还/已经」,用于否定句和疑问句,放在句尾。",
|
||||||
|
body: "“Yet” means “up to now”, and we use it for things we expect to happen. It goes at the very end of the sentence, and it appears in negatives and questions, not in positive statements. Negative: “I haven’t tidied my desk yet.” Question: “Has the post arrived yet?” If the answer is yes, we often reply with “already”: “Yes, it’s already here.”",
|
||||||
|
examples: ["I haven’t done my homework yet.", "Has Dad come home yet?", "The results aren’t here yet."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Positions at a glance",
|
||||||
|
zh: "just、already 放句中,yet 放句尾——记住这张表就够。",
|
||||||
|
body: "The three words share one job: marking recent or expected events in the present perfect. “Just” and “already” sit between the helper and the main verb; “yet” stands alone at the end. Memorise this pattern and you will almost never put them in the wrong place. The table below shows the whole rule in one look, with one sentence for each word.",
|
||||||
|
structure: {
|
||||||
|
cols: ["word", "sentence type", "position", "example"],
|
||||||
|
rows: [
|
||||||
|
["just", "positive", "middle", "I’ve just eaten."],
|
||||||
|
["already", "positive / surprised question", "middle", "She’s already left."],
|
||||||
|
["yet", "negative / question", "end", "Haven’t you finished yet?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["He’s just phoned.", "We’ve already packed.", "I haven’t slept well yet."],
|
||||||
|
note: "疑问句里既可用 yet(中性)也可用 already(惊讶):“Have you eaten already?!”",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I’ve ___ finished my tea — it’s still hot.", options: ["just", "yet", "ever"], answer: 0, explain: "茶还热 = 刚完成,用 just。" },
|
||||||
|
{ q: "Hurry! The film has ___ started.", options: ["yet", "already", "ever"], answer: 1, explain: "肯定句、表中「已经」用 already。" },
|
||||||
|
{ q: "She hasn’t tidied her room ___ .", options: ["already", "just", "yet"], answer: 2, explain: "否定句句尾用 yet。" },
|
||||||
|
{ q: "___ you finished the book yet?", options: ["Have", "Did", "Are"], answer: 0, explain: "现在完成时疑问句用 Have。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "Don’t buy milk — I’ve ___ bought some.", options: ["yet", "just", "ever"], answer: 1, explain: "刚买了一些,用 just。" },
|
||||||
|
{ q: "We’ve ___ seen this film, so let’s pick another.", options: ["already", "yet", "never"], answer: 0, explain: "已经看过,肯定句用 already。" },
|
||||||
|
{ q: "Has the bus arrived ___ ?", options: ["yet", "already", "just"], answer: 0, explain: "一般疑问句句尾用 yet。" },
|
||||||
|
{ q: "I haven’t ___ my grandparents this week.", options: ["visit", "visited", "visiting"], answer: 1, explain: "haven’t 后接过去分词 visited。" },
|
||||||
|
{ q: "He’s ___ left — I saw him at the door a minute ago.", options: ["yet", "just", "ever"], answer: 1, explain: "一分钟前还在门口 = 刚走,用 just。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Present perfect or past simple?",
|
||||||
|
goal: "根据时间线索和与现在的联系,在现在完成时和一般过去时之间正确选择。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "One idea, two tenses",
|
||||||
|
zh: "两个时态都能说过去的事,区别在「意思」而非翻译。",
|
||||||
|
body: "Both tenses can describe past actions, so choosing between them is a question of meaning, not of translating word by word. Use the past simple when the action sits inside a finished time period and has no direct link to now. Use the present perfect when the time is not stated, when the period is not finished, or when the past action still matters at this very moment.",
|
||||||
|
examples: ["I lost my key yesterday.", "I’ve lost my key — I can’t get in!", "She broke her leg in May. (it is healed now)"],
|
||||||
|
note: "判断关键:这事跟「现在」还有没有关系?有关系 → 现在完成时。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Time words decide for you",
|
||||||
|
zh: "看到 yesterday/ago/in 2019 用过去时;看到 ever/since/for 用完成时。",
|
||||||
|
body: "Time expressions are the quickest clue. Words that point to a finished moment — yesterday, last week, in 2019, two days ago, when I was young — pull the sentence into the past simple. Words that connect past and present — ever, never, just, already, yet, since, for, so far, recently — call for the present perfect. If you can see the clue word, the tense usually decides itself.",
|
||||||
|
structure: {
|
||||||
|
cols: ["clue words", "tense", "example"],
|
||||||
|
rows: [
|
||||||
|
["yesterday, last year, … ago, in 2019", "past simple", "I met her in 2019."],
|
||||||
|
["ever, never, just, yet, since, for, so far", "present perfect", "I’ve known her for years."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["He left school two years ago.", "I’ve never been so happy.", "So far, everything is fine."],
|
||||||
|
note: "ago 永远跟一般过去时,绝不与 have 连用。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Starting with experience, asking for details",
|
||||||
|
zh: "先用完成时问「有没有」,再切到过去时问「何时何地」。",
|
||||||
|
body: "In real conversation the two tenses often work together. We open with the present perfect to ask about the experience in general, and then switch to the past simple once a definite time enters the conversation. For example: “Have you ever won a prize?” “Yes, I have.” “When did you win it?” “I won a drawing prize last spring.” The first question has no time; the follow-up questions always do.",
|
||||||
|
examples: ["Have you ever met a famous person? I met a singer last summer.", "Has she travelled much? She went to Japan in April."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Finished and unfinished time periods",
|
||||||
|
zh: "时间段还没过(今天、本周)用完成时;过完了用过去时。",
|
||||||
|
body: "Think about whether the time period itself is still open. “This morning”, “this week”, “today” are still running while we speak, so the present perfect fits: “I’ve drunk three cups of tea this morning.” Once the period closes — it is now the afternoon — the same fact becomes past simple: “I drank three cups this morning.” Finished period, past tense; open period, perfect. The words are the same; the clock decides.",
|
||||||
|
examples: ["I’ve had two lessons today. (still today)", "I had two lessons yesterday.", "This term has flown by."],
|
||||||
|
note: "this morning 在上午说用完成时,到了下午再说同一件事就要用过去时。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I ___ my phone yesterday.", options: ["have lost", "lost", "lose"], answer: 1, explain: "yesterday 是过去时间,用过去时。" },
|
||||||
|
{ q: "I can’t get into the house. I ___ my key.", options: ["lost", "have lost", "did lose"], answer: 1, explain: "现在进不去 = 对现在有影响,用现在完成时。" },
|
||||||
|
{ q: "___ you ever ___ a real snake?", options: ["Did / touch", "Have / touched", "Do / touch"], answer: 1, explain: "问人生经历用 Have you ever + 过去分词。" },
|
||||||
|
{ q: "She ___ to London in 2019.", options: ["has been", "went", "goes"], answer: 1, explain: "in 2019 是过去时间,用 went。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "My uncle ___ in this factory since 2015.", options: ["worked", "has worked", "works"], answer: 1, explain: "since 2015 表示持续到现在,用现在完成时。" },
|
||||||
|
{ q: "We ___ a great film last night.", options: ["have seen", "saw", "see"], answer: 1, explain: "last night 是过去时间,用 saw。" },
|
||||||
|
{ q: "So far this month, I ___ three books.", options: ["read", "have read", "reads"], answer: 1, explain: "so far(到目前为止)用现在完成时。" },
|
||||||
|
{ q: "When ___ you ___ to ride a bike?", options: ["have / learned", "did / learn", "do / learn"], answer: 1, explain: "when 问具体过去时间,用一般过去时。" },
|
||||||
|
{ q: "Shakespeare ___ many famous plays.", options: ["has written", "wrote", "writes"], answer: 1, explain: "莎士比亚已去世,时期结束,用一般过去时。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "for and since; asking “How long …?”",
|
||||||
|
goal: "分清 for(一段时间)与 since(起点),会用 How long 提问持续时间。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "for + a period of time",
|
||||||
|
zh: "for 后接「一段时间」:for two years / ten minutes / a long time。",
|
||||||
|
body: "Use “for” with a length of time — an amount: for ten minutes, for three days, for two years, for a long time, for ages. The phrase answers the question “how much time?” It tells us the size of the whole period, from its beginning to its end, but it does not say when the period started on the calendar. Anything you can count as a stretch of time takes “for”.",
|
||||||
|
examples: ["I’ve known her for ten years.", "They haven’t visited us for months.", "We’ve waited for half an hour."],
|
||||||
|
note: "for 后面不接 when/ago:说 for three years,不说 for three years ago。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "since + a starting point",
|
||||||
|
zh: "since 后接「起点」:since 2020 / Monday / I was six。",
|
||||||
|
body: "Use “since” with the starting point of a period: since Monday, since 2020, since breakfast, since I was six. The phrase answers “from when?” Everything after “since” names the moment the situation began, and the situation continues right up to now. If a clause follows, keep it in a past tense: “since we moved here”, “since she was a baby”. The starting event is past; the situation is still true.",
|
||||||
|
examples: ["We’ve been friends since primary school.", "He’s had this bike since his birthday.", "I’ve loved football since I was five."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Asking “How long …?”",
|
||||||
|
zh: "问持续多久:How long have you + 过去分词 …?回答用 for/since。",
|
||||||
|
body: "To ask about the length of a continuing situation, start with “How long” and use the present perfect: “How long have you lived in this town?” Answer with a “for” or “since” phrase: “For about six years.” / “Since 2020.” The same pattern works with many verbs: “How long has she been a teacher?” “How long have they known each other?” The question always asks about a situation that is still alive now.",
|
||||||
|
examples: ["How long have you studied English?", "How long has it been broken?", "How long have they been married?"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The classic mistake",
|
||||||
|
zh: "从过去持续到现在的状态必须用完成时,不能用 is/know 的现在时。",
|
||||||
|
body: "A very common mistake is using the present simple or continuous with these phrases: “I am here since May” or “I know her for years.” In English, a situation that began in the past and continues now needs the present perfect: “I’ve been here since May.” “I’ve known her for years.” The period started before now and is still true now — that is exactly what the present perfect exists to say.",
|
||||||
|
structure: {
|
||||||
|
cols: ["word", "followed by", "example"],
|
||||||
|
rows: [
|
||||||
|
["for", "a period (how long)", "for three weeks"],
|
||||||
|
["since", "a starting point (when)", "since June / since I was ten"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Wrong: I am here since May. → Right: I’ve been here since May.", "Wrong: I know her for years. → Right: I’ve known her for years."],
|
||||||
|
note: "中文说「我来这儿两个月了」用现在时,英文必须说 I’ve been here for two months。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She has studied English ___ five years.", options: ["for", "since", "during"], answer: 0, explain: "five years 是一段时间,用 for。" },
|
||||||
|
{ q: "I’ve had this dog ___ 2021.", options: ["for", "since", "from"], answer: 1, explain: "2021 是起点,用 since。" },
|
||||||
|
{ q: "How long ___ you ___ this phone?", options: ["have / had", "do / have", "did / have"], answer: 0, explain: "问持续到现在用现在完成时。" },
|
||||||
|
{ q: "He’s been a teacher ___ he was twenty.", options: ["for", "since", "when"], answer: 1, explain: "he was twenty 是起点从句,用 since。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "We’ve waited ___ two hours.", options: ["since", "for", "ago"], answer: 1, explain: "two hours 是一段时间,用 for。" },
|
||||||
|
{ q: "I’ve loved music ___ I was a child.", options: ["for", "since", "from"], answer: 1, explain: "I was a child 是起点,用 since。" },
|
||||||
|
{ q: "How long has she ___ here?", options: ["been", "be", "being"], answer: 0, explain: "has 后接过去分词 been。" },
|
||||||
|
{ q: "They haven’t played tennis ___ last summer.", options: ["since", "for", "during"], answer: 0, explain: "last summer 是起点,用 since。" },
|
||||||
|
{ q: "It hasn’t rained ___ weeks.", options: ["since", "for", "ago"], answer: 1, explain: "weeks 是一段时间,用 for。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "The present perfect continuous",
|
||||||
|
goal: "学会用现在完成进行时 have been doing 强调动作的持续与最近的活动。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Form and core meaning",
|
||||||
|
zh: "have/has been + 动词-ing:从过去开始、一直在做(可能仍在做)。",
|
||||||
|
body: "The present perfect continuous is built with “have/has been” plus the -ing form: “I have been waiting.” It describes an activity that started in the past and is still going on, or has only just stopped. The speaker’s attention is on the activity itself and its length, not on completion. Questions and negatives follow the usual pattern: “Have you been crying?” “I haven’t been sleeping well.”",
|
||||||
|
examples: ["I’ve been studying English since nine o’clock.", "How long have you been waiting?", "He’s been working in the garden all morning."],
|
||||||
|
note: "结构里有两个「零件」都不能少:have been 的 been,和动词的 -ing。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "How long vs. how much",
|
||||||
|
zh: "强调「多久」用进行时;强调「多少成果」用一般完成时。",
|
||||||
|
body: "The continuous form answers “how long” — the length of the activity: “I’ve been reading all afternoon.” The simple present perfect answers “how much / how many” — the finished result: “I’ve read three chapters.” Many verbs of state — know, like, want, believe, and “have” for possession — cannot take the continuous form at all. Say “I’ve known him for years”, never “I’ve been knowing him”.",
|
||||||
|
examples: ["I’ve been reading this book all day. (how long)", "I’ve read three chapters. (how many)", "I’ve had this pen for years. (不用进行时)"],
|
||||||
|
note: "know、like、want 等状态动词没有进行时,只能说 I’ve known,不能说 I’ve been knowing。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Visible evidence in the present",
|
||||||
|
zh: "眼前看得到痕迹,就用进行时解释「刚才一直在干什么」。",
|
||||||
|
body: "We often use this tense to explain something we can see, hear, or smell right now. The evidence sits in the present; the activity that caused it was recent and maybe long. “You’re red in the face — have you been running?” “The kitchen smells of cookies — who’s been baking?” “Her eyes are wet — she’s been crying.” The result is visible; the recent activity left its mark.",
|
||||||
|
examples: ["You’re out of breath — have you been running?", "The ground is wet — it’s been raining.", "Sorry about the noise — I’ve been practising the drums."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Signal words and a comparison",
|
||||||
|
zh: "all day / all morning / lately 是进行时的老朋友。",
|
||||||
|
body: "Certain time phrases are friendly to the continuous form because they stress duration: “all day”, “all morning”, “for hours”, “lately”, “recently”. “He’s been practising the piano all afternoon.” “I’ve been feeling tired lately.” If the sentence paints a picture of time passing rather than counting results, the continuous form is usually the better choice. The table below compares the two present perfect forms side by side.",
|
||||||
|
structure: {
|
||||||
|
cols: ["form", "focus", "example"],
|
||||||
|
rows: [
|
||||||
|
["have been doing", "duration / activity", "I’ve been cleaning all morning."],
|
||||||
|
["have done", "result / completion", "I’ve cleaned the whole house."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["She’s been painting her room — there’s paint on her clothes.", "I’ve been learning to cook recently."],
|
||||||
|
note: "同一件事两种说法都对,只是镜头不同:一个拍过程,一个拍成果。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "You’re red in the face. ___ you ___ ?", options: ["Have / been running", "Did / run", "Do / run"], answer: 0, explain: "眼前的痕迹 + 刚持续的活动,用现在完成进行时。" },
|
||||||
|
{ q: "I ___ this book for two hours, but I’m only on page ten.", options: ["have read", "have been reading", "read"], answer: 1, explain: "强调花了多久(过程),用进行时。" },
|
||||||
|
{ q: "She ___ him since they were children.", options: ["has known", "has been knowing", "is knowing"], answer: 0, explain: "know 是状态动词,没有进行时。" },
|
||||||
|
{ q: "How long ___ they ___ football?", options: ["have / been playing", "are / playing", "did / played"], answer: 0, explain: "how long 问持续,用 have been playing。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "Her eyes are wet. ___ she ___ ?", options: ["Has / been crying", "Did / cried", "Does / cry"], answer: 0, explain: "眼睛湿是眼前证据,用现在完成进行时。" },
|
||||||
|
{ q: "I’m tired because I ___ all morning.", options: ["have been cleaning", "clean", "am cleaning"], answer: 0, explain: "all morning 的持续活动导致现在的累。" },
|
||||||
|
{ q: "We ___ each other for six years.", options: ["have been knowing", "have known", "know"], answer: 1, explain: "know 是状态动词,用现在完成时 have known。" },
|
||||||
|
{ q: "How many pages ___ you ___ so far?", options: ["have / been reading", "have / read", "are / reading"], answer: 1, explain: "how many 问数量/成果,用一般完成时。" },
|
||||||
|
{ q: "The path is muddy because it ___ .", options: ["has been raining", "rains", "is raining"], answer: 0, explain: "路泥是最近下雨的痕迹,用现在完成进行时。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "must / have to / mustn’t (obligation and prohibition)",
|
||||||
|
goal: "用 must / have to 表达义务,用 mustn't 表达禁止,并区分 don't have to。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "must and have to — both mean “necessary”",
|
||||||
|
zh: "must 偏「我觉得必须」,have to 偏「规定/客观上不得不」。",
|
||||||
|
body: "Both “must” and “have to” say that something is necessary, but the feeling comes from different places. “Must” usually expresses the speaker’s own feeling: “I must phone my grandma — I keep forgetting.” “Have to” usually reports an outside rule or fact: “We have to wear a uniform at school.” Form: “must” + base verb, with no -s and no “to”; “have to” changes with person and tense: has to, had to, will have to.",
|
||||||
|
examples: ["I must finish my homework before dinner.", "Students have to wear a uniform here.", "She has to start work at eight."],
|
||||||
|
note: "must 后直接加动词原形,不能写 must to go;he/she 也不加 s。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "mustn’t and don’t have to — very different",
|
||||||
|
zh: "mustn't = 禁止做;don't have to = 不必做(想做也行)。",
|
||||||
|
body: "The negative forms mean completely different things, so learn them as a pair. “Mustn’t” means “do not do it — it is forbidden”: “You mustn’t feed the animals at the zoo.” “Don’t have to” means “it is not necessary — you can if you want, but you needn’t”: “You don’t have to bring food; there’s plenty.” Mixing these two up can turn a kind offer into a strict rule.",
|
||||||
|
examples: ["You mustn’t talk in the library.", "You don’t have to come on Sunday — it’s optional.", "We mustn’t be late for the show."],
|
||||||
|
note: "「你不必来」是 You don’t have to come;说成 You mustn’t come 就变成「禁止你来」。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Other tenses and questions",
|
||||||
|
zh: "must 没有过去/将来形式,都用 have to 代替。",
|
||||||
|
body: "“Must” is a small, stubborn word: it has no past, no future, and no -ing form. When we need those, “have to” steps in: “I had to walk home yesterday.” “You will have to show your ticket.” In questions we normally use “have to” as well: “Do I have to wear a tie?” “Must I…?” exists but sounds formal and old-fashioned. The negative “didn’t have to” keeps the meaning “it was not necessary”.",
|
||||||
|
examples: ["I had to walk home because the bus broke down.", "Will we have to cook tonight?", "Do you have to leave so soon?"],
|
||||||
|
note: "昨天的「必须」说 had to,明天的「必须」说 will have to,千万别造 musted。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The whole system on one page",
|
||||||
|
zh: "四种意思、四个形式,对照这张表一次记牢。",
|
||||||
|
body: "Here is the whole system at a glance. Necessity from inside: must. Necessity from rules or facts: have to. Prohibition: mustn’t. No necessity: don’t have to. Past necessity: had to. Read the four example sentences in the table out loud; between them they cover almost every daily situation — school rules, traffic signs, free weekends, and yesterday’s chores.",
|
||||||
|
structure: {
|
||||||
|
cols: ["meaning", "form", "example"],
|
||||||
|
rows: [
|
||||||
|
["I feel it is necessary", "must", "I must study harder."],
|
||||||
|
["a rule makes it necessary", "have to", "You have to stop at a red light."],
|
||||||
|
["it is forbidden", "mustn’t", "You mustn’t swim here."],
|
||||||
|
["it is not necessary", "don’t have to", "You don’t have to pay."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I must tidy my room. (my own decision)", "We had to queue for an hour yesterday."],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "You ___ smoke in hospital. It’s against the rules.", options: ["mustn’t", "don’t have to", "must"], answer: 0, explain: "医院禁烟 = 禁止,用 mustn’t。" },
|
||||||
|
{ q: "Tomorrow is a holiday. You ___ get up early.", options: ["mustn’t", "don’t have to", "have to"], answer: 1, explain: "不必早起(想起也行),用 don’t have to。" },
|
||||||
|
{ q: "She ___ wear a uniform at work — it’s the rule.", options: ["must to", "has to", "have to"], answer: 1, explain: "she 用 has to;must 后不加 to。" },
|
||||||
|
{ q: "I’m exhausted. I ___ go to bed early tonight.", options: ["must", "mustn’t", "don’t have to"], answer: 0, explain: "自己觉得必须早睡,用 must。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "You ___ touch that wire! It’s dangerous.", options: ["don’t have to", "mustn’t", "must"], answer: 1, explain: "危险 = 禁止触碰,用 mustn’t。" },
|
||||||
|
{ q: "We ___ buy tickets — entry is free today.", options: ["don’t have to", "have to", "mustn’t"], answer: 0, explain: "免费 = 不必买票,用 don’t have to。" },
|
||||||
|
{ q: "He ___ leave early yesterday because of the storm.", options: ["had to", "must", "has to"], answer: 0, explain: "must 没有过去式,昨天用 had to。" },
|
||||||
|
{ q: "I ___ remember to call Grandma — it’s her birthday today.", options: ["must", "mustn’t", "don’t have to"], answer: 0, explain: "自己提醒自己的义务,用 must。" },
|
||||||
|
{ q: "You ___ drive so fast here — the limit is 40.", options: ["don’t have to", "must", "mustn’t"], answer: 2, explain: "限速 = 禁止超速,用 mustn’t。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "weekly",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "第 6 周测验",
|
||||||
|
intro: "本周你学了现在完成时家族:人生经历、just / already / yet、与一般过去时的区别、for 与 since、现在完成进行时,以及 must / have to / mustn't。下面 10 题综合检测,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "She ___ to Paris three times.", options: ["has been", "is", "was"], answer: 0, explain: "数人生经历次数用 has been to。" },
|
||||||
|
{ q: "Watch out — I’ve ___ mopped the floor.", options: ["yet", "just", "ever"], answer: 1, explain: "刚拖完、地还湿,用 just。" },
|
||||||
|
{ q: "Have you packed your schoolbag ___ ?", options: ["already", "yet", "just"], answer: 1, explain: "疑问句句尾用 yet。" },
|
||||||
|
{ q: "My parents ___ married in 1998.", options: ["have got", "got", "get"], answer: 1, explain: "in 1998 是过去时间,用一般过去时 got。" },
|
||||||
|
{ q: "I’ve had this phone ___ two years.", options: ["since", "for", "from"], answer: 1, explain: "two years 是一段时间,用 for。" },
|
||||||
|
{ q: "How long ___ you ___ Chinese?", options: ["have / studied", "did / studied", "do / study"], answer: 0, explain: "问持续至今的时间用现在完成时。" },
|
||||||
|
{ q: "Sorry I’m late. ___ you ___ long?", options: ["Have / been waiting", "Are / waiting", "Did / waited"], answer: 0, explain: "对持续等待用现在完成进行时。" },
|
||||||
|
{ q: "You ___ feed the animals in the zoo.", options: ["don’t have to", "mustn’t", "must"], answer: 1, explain: "动物园规定禁止投喂,用 mustn’t。" },
|
||||||
|
{ q: "You ___ cook tonight — let’s eat out.", options: ["mustn’t", "don’t have to", "have to"], answer: 1, explain: "不必做饭(出去吃),用 don’t have to。" },
|
||||||
|
{ q: "Where’s Sam? — He’s ___ the bank. He’ll be back soon.", options: ["gone to", "been to", "went to"], answer: 0, explain: "他还没回来,用 has gone to。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,361 @@
|
|||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 第 7 周:B1 —— 建议(should / ought to)、可能性(may / might / could)、
|
||||||
|
// 第一与第二条件句、wish(对现在的遗憾)、短语动词入门(可分与不可分)
|
||||||
|
// 全部讲解、例句、练习、测验均为原创,仅使用语法主题名称,不参考任何书籍正文。
|
||||||
|
|
||||||
|
export const week07: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "should / shouldn’t and ought to (advice)",
|
||||||
|
goal: "学会用 should / shouldn't 和 ought to 提建议,并会向别人征求建议。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "should and shouldn’t",
|
||||||
|
zh: "should = 这样做比较好;shouldn't = 最好不要;都是温和建议。",
|
||||||
|
body: "Use “should” and “shouldn’t” to give advice — to say what is a good or a bad idea. They are softer than “must”: nobody is forcing anyone. “You look tired. You should go to bed early.” “You shouldn’t eat sweets before brushing your teeth.” The form never changes: “should” for every person, followed by the base verb with no “to”: “She should rest.”, never “She should to rest.”",
|
||||||
|
examples: ["You look tired. You should go to bed early.", "You shouldn’t drink so much cola.", "We should write down new words."],
|
||||||
|
note: "should 后永远是动词原形,没有人称变化:she should,不是 she shoulds。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "ought to — a formal twin of should",
|
||||||
|
zh: "ought to 意思和 should 几乎一样,更正式,否定是 ought not to。",
|
||||||
|
body: "“Ought to” means the same as “should”, and the two can usually swap: “We ought to visit Grandma more often.” It sounds a little more formal and is more common in writing than in fast speech. The negative is “ought not to”, though in ordinary conversation most people simply use “shouldn’t”. Remember the “to” — it is part of the phrase: “You ought to apologise.”",
|
||||||
|
examples: ["You ought to thank her for the gift.", "We ought not to waste food.", "He ought to see a doctor."],
|
||||||
|
note: "ought 必须带 to;只写 “You ought go” 是错的。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Asking for advice; had better",
|
||||||
|
zh: "用 Should I…? / What should I…? 征求建议;had better 语气更强,带警告。",
|
||||||
|
body: "To ask for advice, use a question with “should”: “Should I tell her the truth?” “What should I buy for Dad’s birthday?” “Where should we eat tonight?” For stronger advice — close to a warning — use “had better”, usually shortened to “’d better”: “You’d better hurry, or you’ll miss the bus.” “Had better” suggests a bad result if the advice is ignored, so it sounds more urgent than “should”.",
|
||||||
|
examples: ["Should I call her first?", "What should I wear to the party?", "You’d better take an umbrella — those clouds look dark."],
|
||||||
|
note: "had better 后也用动词原形:You’d better go,不是 You’d better to go。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Three strengths of advice",
|
||||||
|
zh: "友好建议用 should/ought to,带后果提醒用 had better,强义务才是 must。",
|
||||||
|
body: "Advice has three strengths. “Should / ought to” give friendly suggestions. “Had better” adds a quiet warning about consequences. And “must” — which you met last week — expresses strong necessity. Choosing the right strength matters: telling a friend “You must see this film!” shows enthusiasm, while “You should see a doctor” shows gentle concern. The table below lines up form, strength, and example.",
|
||||||
|
structure: {
|
||||||
|
cols: ["form", "strength", "example"],
|
||||||
|
rows: [
|
||||||
|
["should / ought to", "friendly suggestion", "You should rest today."],
|
||||||
|
["had better", "warning: bad result if not", "You’d better leave now."],
|
||||||
|
["must", "strong necessity", "You must wear a helmet."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["You ought to try the cake — it’s great.", "You’d better not be late again."],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "You’ve got a test tomorrow. You ___ go to bed early.", options: ["should", "shouldn’t", "ought"], answer: 0, explain: "提温和建议用 should;ought 缺了 to。" },
|
||||||
|
{ q: "You ___ eat junk food every day — it’s bad for you.", options: ["should", "shouldn’t", "should to"], answer: 1, explain: "不好的习惯,劝不要,用 shouldn’t。" },
|
||||||
|
{ q: "We ___ to thank our teacher for her help.", options: ["should", "ought", "must"], answer: 1, explain: "带 to 的是 ought。" },
|
||||||
|
{ q: "___ I call her and say sorry?", options: ["Should", "Ought", "Must to"], answer: 0, explain: "征求建议用 Should I…?;ought 缺 to,must 不带 to。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "It’s raining. You ___ take a raincoat.", options: ["should", "shouldn’t", "ought"], answer: 0, explain: "温和建议用 should。" },
|
||||||
|
{ q: "You ___ shout at your little brother.", options: ["should", "shouldn’t", "should to"], answer: 1, explain: "劝止大声吼叫,用 shouldn’t。" },
|
||||||
|
{ q: "You really ought ___ see a doctor.", options: ["—", "to", "for"], answer: 1, explain: "ought 后必须接 to。" },
|
||||||
|
{ q: "What ___ I do now?", options: ["should", "ought", "must to"], answer: 0, explain: "征求建议:What should I do?" },
|
||||||
|
{ q: "You’d ___ finish your vegetables before dessert.", options: ["better", "should", "ought"], answer: 0, explain: "You’d better = You had better。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "may / might / could (possibility)",
|
||||||
|
goal: "学会用 may / might / could 表达可能性与猜测,区分 can't 表「不可能」。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Three words for “perhaps”",
|
||||||
|
zh: "may / might / could + 动词原形,都表示「也许、可能」。",
|
||||||
|
body: "“May”, “might”, and “could” all say that something is possible — perhaps true, perhaps not. “It might rain later.” “She may be at the library.” “The parcel could arrive tomorrow.” In everyday speech “might” and “could” are the most common; “may” sounds a touch more formal. Roughly, “may” suggests a slightly stronger chance than “might”, but the difference is small — native speakers mix them freely.",
|
||||||
|
examples: ["Take a coat. It might get cold tonight.", "Where’s Dad? He may be in the garden.", "I’m not sure, but it could be true."],
|
||||||
|
note: "这三个词后都接动词原形,且没有人称变化:it might,不是 it mights。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Don’t use “can” for one-off guesses",
|
||||||
|
zh: "can 表能力/许可;对具体一件事的猜测要用 might,不用 can。",
|
||||||
|
body: "Be careful with “can”. It expresses ability (“She can swim”) and permission (“You can go now”), but we do not normally use it to guess about one particular situation. “It can rain tomorrow” sounds wrong; say “It might rain tomorrow.” However, “can” does work for general, repeated possibilities: “Winters here can be very cold.” For one-off guesses about the present or future, keep to may, might, and could.",
|
||||||
|
examples: ["It might rain tomorrow. (不用 can)", "Even experts can make mistakes. (泛指)", "That could be his car outside."],
|
||||||
|
note: "「明天可能下雨」是 It might rain,说 It can rain 是典型中式错误。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Negatives: uncertain vs. almost certain",
|
||||||
|
zh: "might not = 也许不;can't / couldn't = 几乎确定不可能。",
|
||||||
|
body: "The negatives split into two meanings. “May not” and “might not” mean “perhaps not” — the situation is still open: “They might not come to the party.” “Couldn’t” (and “can’t”) mean the opposite: you feel almost sure something is impossible. “He can’t be at home — his bike isn’t here.” “Couldn’t” is the negative guess; “might not” is the uncertain guess. Never use “mustn’t” for guessing — it means prohibition.",
|
||||||
|
examples: ["They might not arrive before eight.", "She can’t be asleep — her light is on.", "That couldn’t be true."],
|
||||||
|
note: "mustn’t 只表「禁止」,绝不表猜测;「他不可能在家」是 He can’t be at home。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Polite requests and a summary",
|
||||||
|
zh: "Could you…? / Could I…? 是礼貌请求;可能性提问常用 Do you think…?",
|
||||||
|
body: "We rarely start a possibility question with “May it…?” or “Might it…?” — that sounds very stiff. Instead, ask “Do you think it will rain?” or “Could it be true?” “Could” is, however, perfect for polite requests: “Could you open the window?” “Could I borrow your rubber?” The table summarises the three jobs: a weak guess, a near-certain negative guess, and a polite request.",
|
||||||
|
structure: {
|
||||||
|
cols: ["job", "words", "example"],
|
||||||
|
rows: [
|
||||||
|
["weak guess (perhaps)", "may / might / could", "It might snow."],
|
||||||
|
["almost sure “no”", "can’t / couldn’t", "It can’t be Monday today."],
|
||||||
|
["polite request", "could", "Could you help me?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Could I use your phone?", "Do you think she might come?"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "It’s very cloudy. It ___ rain later.", options: ["might", "mustn’t", "should to"], answer: 0, explain: "猜测天气可能下雨,用 might。" },
|
||||||
|
{ q: "He ___ be at school — it’s Sunday!", options: ["might", "may", "can’t"], answer: 2, explain: "周日不可能在学校,用 can’t 表近乎确定的否定猜测。" },
|
||||||
|
{ q: "I’m not sure, but she ___ come to the party.", options: ["mustn’t", "can’t", "may"], answer: 2, explain: "不确定但有可能,用 may。" },
|
||||||
|
{ q: "___ you help me with this box, please?", options: ["Could", "Must", "Should"], answer: 0, explain: "礼貌请求用 Could you…?" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "Hurry up! We ___ miss the bus.", options: ["might", "mustn’t", "can’t"], answer: 0, explain: "有可能错过,用 might。" },
|
||||||
|
{ q: "That ___ be Tom — Tom is in Beijing this week.", options: ["may", "can’t", "could"], answer: 1, explain: "人在北京,不可能是他,用 can’t。" },
|
||||||
|
{ q: "Ask Anna. She ___ know the answer.", options: ["mustn’t", "can’t", "might"], answer: 2, explain: "她也许知道,用 might。" },
|
||||||
|
{ q: "They ___ not like the food — they ate very little.", options: ["may", "can", "must to"], answer: 0, explain: "也许不喜欢(不确定),用 may not。" },
|
||||||
|
{ q: "___ I borrow your dictionary?", options: ["Could", "Must", "Should"], answer: 0, explain: "礼貌请求许可用 Could I…?" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "The first conditional (if + present, will)",
|
||||||
|
goal: "掌握第一条件句「if + 现在时, will」的结构,描述真实可能的未来。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Form: a real possible future",
|
||||||
|
zh: "if 从句用一般现在时,主句用 will + 动词原形,说可能发生的事。",
|
||||||
|
body: "The first conditional describes a real, possible future: if the condition happens, the result will follow. The if-clause uses the present simple; the main clause uses “will” plus the base verb. “If it rains tomorrow, we will stay at home.” The condition is not certain — maybe it will rain, maybe not — but it is a genuine possibility, not a dream. In speech, “will” nearly always becomes “’ll”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["clause", "tense", "example"],
|
||||||
|
rows: [
|
||||||
|
["if-clause (condition)", "present simple", "If it rains,"],
|
||||||
|
["main clause (result)", "will + base verb", "we’ll stay at home."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["If it rains tomorrow, we’ll stay at home.", "If you don’t hurry, you’ll miss the train.", "She’ll be cross if you forget her birthday."],
|
||||||
|
note: "第一条件句说的是「真的可能发生」的事,不是幻想。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Two orders, one meaning",
|
||||||
|
zh: "if 从句可前可后;放句首要加逗号,放句后不用。",
|
||||||
|
body: "The two clauses can swap places without changing the meaning. If the if-clause comes first, put a comma after it: “If you hurry, you’ll catch the bus.” If the main clause comes first, no comma is needed: “You’ll catch the bus if you hurry.” The second version is actually more common in casual speech. Either order is correct — choose whichever sounds smoother in your sentence.",
|
||||||
|
examples: ["If I finish early, I’ll call you.", "I’ll call you if I finish early.", "We’ll go to the park if the weather is nice."],
|
||||||
|
note: "逗号只跟「if 在前」走;if 从句在后,句中不加逗号。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Other modals in the main clause",
|
||||||
|
zh: "主句不一定用 will,也可以用 can / may / must,甚至祈使句。",
|
||||||
|
body: "The main clause does not have to use “will”. Other modals fit perfectly when the meaning calls for them: “If you finish early, you can go out and play.” (permission) “If she practises every day, she may win the contest.” (weak possibility) “If the light is red, you must stop.” (necessity) An imperative also works: “If you see Tom, tell him to call me.” Whatever you choose, the if-clause still stays in the present tense.",
|
||||||
|
examples: ["If you finish early, you can go out and play.", "If the light is red, you must stop.", "If you see Mike, tell him to phone me."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Keep “will” out of the if-clause",
|
||||||
|
zh: "最常见的错误:在 if 从句里写 will——will 只能待在主句。",
|
||||||
|
body: "The number-one mistake is putting “will” inside the if-clause: “If it will rain…” is wrong in ordinary conditional sentences. The rule is simple: “will” lives in the main clause; the if-clause takes a present tense, even though the meaning is future. The same rule applies to negatives: “If you don’t wear a coat, you’ll catch a cold.” — not “If you won’t wear”. Keep “will” out of the “if” half, and you are safe.",
|
||||||
|
examples: ["Wrong: If it will rain… → Right: If it rains…", "If you don’t wear a coat, you’ll catch a cold."],
|
||||||
|
note: "中文说「如果明天将会下雨」,英文 if 里绝不能有 will:If it rains tomorrow。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "If it ___ sunny tomorrow, we’ll have a picnic.", options: ["is", "will be", "was"], answer: 0, explain: "if 从句用一般现在时 is。" },
|
||||||
|
{ q: "I’ll be happy if you ___ .", options: ["will come", "come", "came"], answer: 1, explain: "if 从句不用 will,用原形 come。" },
|
||||||
|
{ q: "If you ___ now, you’ll catch the bus.", options: ["leave", "will leave", "left"], answer: 0, explain: "if 从句用现在时 leave。" },
|
||||||
|
{ q: "If she ___ hard, she will pass.", options: ["study", "studies", "will study"], answer: 1, explain: "she 第三人称单数,现在时加 -s:studies。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "If I ___ time tonight, I’ll read a book.", options: ["will have", "have", "had"], answer: 1, explain: "if 从句用一般现在时 have。" },
|
||||||
|
{ q: "We’ll get wet if it ___ .", options: ["will rain", "rained", "rains"], answer: 2, explain: "if 从句现在时,it rains。" },
|
||||||
|
{ q: "If you ___ a coat, you’ll feel cold.", options: ["don’t wear", "won’t wear", "didn’t wear"], answer: 0, explain: "if 从句否定用 don’t + 原形。" },
|
||||||
|
{ q: "What will you do if it ___ tomorrow?", options: ["snows", "will snow", "snowed"], answer: 0, explain: "if 从句用现在时 snows。" },
|
||||||
|
{ q: "If he ___ , tell him I said hello.", options: ["will come", "comes", "came"], answer: 1, explain: "if 从句现在时 comes;主句是祈使句。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "The second conditional (if + past, would)",
|
||||||
|
goal: "掌握第二条件句「if + 过去时, would」的结构,描述不真实或极不可能的情况。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Form: the imaginary present",
|
||||||
|
zh: "if 从句用一般过去时,主句用 would + 动词原形,说想象的事。",
|
||||||
|
body: "The second conditional talks about imaginary, unreal, or very unlikely present and future situations. The if-clause uses the past simple; the main clause uses “would” plus the base verb. “If I had a million yuan, I would buy a house by the sea.” I do not have a million yuan — I am just imagining. The past tense here does not mean past time; it marks distance from reality.",
|
||||||
|
examples: ["If I had a million yuan, I would buy a big house.", "If we lived by the sea, we’d swim every day.", "She’d travel more if she had the money."],
|
||||||
|
note: "这里的「过去时」不表过去,而表「离现实很远」——这是第二条件句的灵魂。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "If I were …",
|
||||||
|
zh: "正式写法里所有人称都用 were:If I were you…(口语 was 也常见)。",
|
||||||
|
body: "In careful English, the second conditional uses “were” for every person: “If I were rich…”, “If she were here…” You will also hear “was” in everyday speech — “If I was rich” — and it is not a serious mistake, but “were” is always safe, especially in writing and tests. The fixed phrase “If I were you” is the standard way to give strong advice: “If I were you, I’d apologise.”",
|
||||||
|
examples: ["If I were you, I’d say sorry.", "If she were taller, she could join the basketball team.", "If he were here, he’d know what to do."],
|
||||||
|
note: "考试中遇到 If I ___ you,一律选 were。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "would, could, might in the main clause",
|
||||||
|
zh: "主句用 would 表「就会」,could 表「就能」,might 表「也许会」。",
|
||||||
|
body: "“Would” gives a certain imaginary result, but other modals add shades of meaning. “Could” means “would be able to”: “If I had a bike, I could ride to school.” “Might” means “would perhaps”: “If we asked nicely, they might say yes.” The negative “wouldn’t” describes what we would choose not to do: “If I were you, I wouldn’t eat that.” All three keep the if-clause in the past simple.",
|
||||||
|
examples: ["If I had a bike, I could ride to school.", "If we asked nicely, they might say yes.", "I wouldn’t worry if I were you."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "First or second?",
|
||||||
|
zh: "可能发生用第一条件句;想象/极不可能用第二条件句,时态整体退一步。",
|
||||||
|
body: "First or second? Ask yourself how real the condition is. A real possibility — maybe it will happen — takes the first conditional: “If I save enough, I’ll buy a phone.” An unreal or very unlikely situation takes the second: “If I won a million, I’d travel the world.” The tenses shift one step back, and “will” becomes “would”. The table puts the two structures side by side so you can compare them.",
|
||||||
|
structure: {
|
||||||
|
cols: ["conditional", "structure", "meaning", "example"],
|
||||||
|
rows: [
|
||||||
|
["first", "if + present, will", "real / possible", "If I win, I’ll buy a bike."],
|
||||||
|
["second", "if + past, would", "unreal / unlikely", "If I won, I’d buy a bike."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["If it snows, we’ll make a snowman. (可能)", "If I were a snowman, I’d melt in spring. (想象)"],
|
||||||
|
note: "同一个动词:第一条件句说 If I win,第二条件句说 If I won——一字之差,真实与想象之别。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "If I ___ rich, I’d travel around the world.", options: ["am", "were", "will be"], answer: 1, explain: "第二条件句 if 从句用过去时,be 用 were。" },
|
||||||
|
{ q: "She ___ be cross if you told her the truth.", options: ["would", "will", "can"], answer: 0, explain: "if 从句 told 是过去时 → 主句用 would。" },
|
||||||
|
{ q: "If he ___ more free time, he would learn the guitar.", options: ["has", "had", "will have"], answer: 1, explain: "if 从句用过去时 had。" },
|
||||||
|
{ q: "What ___ you do if you lost your phone?", options: ["will", "would", "do"], answer: 1, explain: "if 从句 lost 是过去时 → 主句用 would。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "If I ___ you, I’d say sorry to her.", options: ["am", "were", "will be"], answer: 1, explain: "If I were you 是固定建议句式。" },
|
||||||
|
{ q: "If she studied harder, she ___ better marks.", options: ["would get", "gets", "will get"], answer: 0, explain: "if 从句 studied 是过去时 → 主句用 would get。" },
|
||||||
|
{ q: "I ___ buy that jacket if it were cheaper.", options: ["would", "will", "am going to"], answer: 0, explain: "if 从句 were 是过去时 → 主句用 would。" },
|
||||||
|
{ q: "If we ___ in Australia, we’d see kangaroos every day.", options: ["lived", "live", "will live"], answer: 0, explain: "想象的情况,if 从句用过去时 lived。" },
|
||||||
|
{ q: "What would you do if someone ___ you a million yuan?", options: ["offers", "offered", "will offer"], answer: 1, explain: "主句 would → if 从句用过去时 offered。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "wish (wishing the present were different)",
|
||||||
|
goal: "学会用 wish + 过去时表达对现在状况的不满或遗憾。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "wish + past simple",
|
||||||
|
zh: "wish 后用过去时,表示「希望现在的情况不是这样」。",
|
||||||
|
body: "Use “wish” plus a past tense to say that you want the present to be different from what it really is. “I wish I had a bike.” The sad fact behind it: I do not have a bike. The verb moves one step back into the past, but the meaning is about now, not about yesterday. Other examples: “She wishes she lived closer.” (she doesn’t) “I wish it wasn’t so cold.” (it is).",
|
||||||
|
examples: ["I wish I had more free time.", "She wishes she lived closer to school.", "We wish we didn’t have so much homework."],
|
||||||
|
note: "wish 后的「过去时」说的是现在:I wish I had = 我真希望我现在有(其实没有)。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "wish + were",
|
||||||
|
zh: "wish 后的 be 各人称都用 were:I wish I were taller。",
|
||||||
|
body: "With “be”, careful English uses “were” for all persons after “wish”: “I wish I were taller.” “He wishes he were braver.” In casual speech “was” appears too — “I wish I was taller” — and people will understand you, but “were” is the safe form for tests and writing. Notice the pattern: the wish is usually about a quality you cannot simply choose, which is exactly why it stays a wish.",
|
||||||
|
examples: ["I wish I were as tall as my brother.", "She wishes she were better at maths.", "I wish it weren’t Monday."],
|
||||||
|
note: "与第二条件句一样,wish 后的 be 优先用 were,考试尤其如此。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "wish + could",
|
||||||
|
zh: "wish + could 表示希望自己能做某事(其实不能)。",
|
||||||
|
body: "“Wish” plus “could” expresses a wish about ability or possibility — something you are not able to do and feel sad about. “I wish I could swim.” (I can’t) “She wishes she could come to the party.” (she can’t) “Could” here is the past form of “can”, following the same backshift rule as everything after “wish”. Do not use “can” after “wish”: “I wish I can swim” is a common learner error.",
|
||||||
|
examples: ["I wish I could play the piano.", "He wishes he could speak French.", "I wish I could help you."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "wish vs. hope",
|
||||||
|
zh: "hope 用于可能发生的将来;wish + 过去时用于不真实的现在。",
|
||||||
|
body: "Do not mix up “wish” and “hope”. “Hope” looks at possible futures — things that may really happen: “I hope you pass the exam.” “Wish” with a past tense looks at unreal presents — things that are not true: “I wish I were on holiday.” (I’m not) Rule of thumb: if it might still happen, use “hope”; if you are complaining about reality, use “wish”. The table below compares them side by side.",
|
||||||
|
structure: {
|
||||||
|
cols: ["word", "about", "example"],
|
||||||
|
rows: [
|
||||||
|
["hope", "possible future", "I hope it’s sunny tomorrow."],
|
||||||
|
["wish + past", "unreal present", "I wish it were sunny. (it isn’t)"],
|
||||||
|
["wish + could", "wished-for ability", "I wish I could fly."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["I hope you feel better soon.", "I wish I were on holiday right now."],
|
||||||
|
note: "「希望你考试通过」是 I hope you pass,不能用 wish——那是可能成真的事。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I’m short. I wish I ___ taller.", options: ["were", "am", "will be"], answer: 0, explain: "wish 后 be 用 were。" },
|
||||||
|
{ q: "I wish I ___ speak French.", options: ["can", "will", "could"], answer: 2, explain: "wish 后 can 要退一步成 could。" },
|
||||||
|
{ q: "She wishes she ___ a car. (she doesn’t)", options: ["has", "had", "have"], answer: 1, explain: "wish 后动词退一步成过去时 had。" },
|
||||||
|
{ q: "I ___ you pass the exam! (可能成真)", options: ["hope", "wish", "wanted"], answer: 0, explain: "可能成真的将来用 hope。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "It’s freezing. I wish I ___ at home.", options: ["were", "am", "will be"], answer: 0, explain: "wish 后 be 用 were。" },
|
||||||
|
{ q: "I can’t cook. I wish I ___ .", options: ["can", "may", "could"], answer: 2, explain: "wish 后表能力用 could。" },
|
||||||
|
{ q: "He wishes he ___ so shy.", options: ["isn’t", "won’t be", "weren’t"], answer: 2, explain: "wish 后 be 的否定用 weren’t。" },
|
||||||
|
{ q: "I wish my phone ___ newer.", options: ["is", "will be", "were"], answer: 2, explain: "wish 后 be 用 were。" },
|
||||||
|
{ q: "They wish they ___ on holiday right now.", options: ["are", "were", "will be"], answer: 1, explain: "wish 后 be 用 were,说的是现在。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Introduction to phrasal verbs: meaning, separable and inseparable",
|
||||||
|
goal: "理解短语动词含义不可猜,并掌握可分与不可分短语动词的宾语位置规则。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "What is a phrasal verb?",
|
||||||
|
zh: "动词 + 小词(副词/介词)= 新意思,往往不能按字面猜。",
|
||||||
|
body: "A phrasal verb is a verb plus a small particle — an adverb or a preposition — and together they make a new meaning. “Look” means to see; “look after” means to take care of. “Give” means to hand over; “give up” means to stop trying. Because the meaning often cannot be guessed from the two words, treat each phrasal verb as one vocabulary item and learn it with an example sentence.",
|
||||||
|
examples: ["She looks after her little brother after school.", "Don’t give up — try again!", "Please turn off the TV."],
|
||||||
|
note: "短语动词的意思常常「不讲道理」,必须整体记忆,别逐字翻译。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Separable phrasal verbs",
|
||||||
|
zh: "可分动词:名词宾语放中间或后面都行,代词宾语必须放中间。",
|
||||||
|
body: "Many phrasal verbs are separable: the object can go after the particle or between the verb and the particle. “Turn off the light.” and “Turn the light off.” are both correct. But there is one hard rule: if the object is a pronoun — it, them, me, her — it must go in the middle. “Turn it off.” is correct; “Turn off it.” is wrong. Small word, strict position.",
|
||||||
|
examples: ["Turn the TV off. / Turn off the TV.", "Turn it off. (不能说 Turn off it.)", "Pick your toys up. / Pick them up."],
|
||||||
|
note: "代词(it/them/me…)永远夹在中间:turn it off ✓,turn off it ✗。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Inseparable phrasal verbs",
|
||||||
|
zh: "不可分动词:宾语只能放在小词后面,不能插到中间。",
|
||||||
|
body: "Other phrasal verbs are inseparable: the object must stay after the particle, never in the middle. “She looks after her little brother.” — never “She looks her little brother after.” This group includes verbs whose particle behaves like a preposition, such as look after, look for, listen to, wait for, and take after. A useful memory hook: if the particle needs its own object right behind it, the two words stay glued together.",
|
||||||
|
examples: ["Who looks after you after school?", "I’m looking for my keys.", "He takes after his father."],
|
||||||
|
note: "look for / look after 这类带介词性小词的动词,宾语只能殿后,不能插队。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Learning them without fear",
|
||||||
|
zh: "按使用场景整块记(穿衣 put on、整理 pick up、查明 find out),别死背分类。",
|
||||||
|
body: "Three-part verbs (“look forward to”, “put up with”) are always inseparable, and a few phrasal verbs have no object at all: get up, sit down, grow up. You do not need to memorise every type now — just notice the pattern when you meet a new one. Learn phrasal verbs in the situations where you actually use them: getting dressed (put on), tidying (pick up), discovering things (find out).",
|
||||||
|
structure: {
|
||||||
|
cols: ["type", "rule", "example"],
|
||||||
|
rows: [
|
||||||
|
["separable", "pronoun object goes in the middle", "turn it off"],
|
||||||
|
["inseparable", "object stays after the particle", "look after my sister"],
|
||||||
|
["no object", "just verb + particle", "get up / sit down"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["He put on his coat and left.", "Let’s find out the time of the train."],
|
||||||
|
note: "同一个动词加不同小词意思完全不同:put on(穿上)、put off(推迟)、put up(张贴)——按场景一个个记。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "The music is too loud. Turn ___ down.", options: ["it", "off it", "it off"], answer: 0, explain: "turn down 中间放代词 it。" },
|
||||||
|
{ q: "Who looks ___ you after school?", options: ["you after", "after", "up"], answer: 1, explain: "look after 不可分,小词 after 紧跟 looks。" },
|
||||||
|
{ q: "Your bag is on the floor. Pick ___ up.", options: ["it", "up it", "it up"], answer: 0, explain: "pick up 可分,代词 it 放中间。" },
|
||||||
|
{ q: "The plane took ___ at nine this morning.", options: ["off", "it off", "off it"], answer: 0, explain: "take off(起飞)不带宾语,小词 off 直接跟上。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "Which sentence is correct?", options: ["Turn off it.", "Turn it off.", "Turn it off it."], answer: 1, explain: "代词宾语必须放中间:Turn it off。" },
|
||||||
|
{ q: "Which sentence is correct?", options: ["She looks her cat after.", "She looks after her cat.", "She looks it after."], answer: 1, explain: "look after 不可分,宾语放小词后。" },
|
||||||
|
{ q: "The TV is too quiet. Turn ___ .", options: ["down it", "it up", "up it"], answer: 1, explain: "调大音量是 turn up,代词 it 放中间:turn it up。" },
|
||||||
|
{ q: "Don’t ___ up — keep trying!", options: ["give", "take", "look"], answer: 0, explain: "give up = 放弃。" },
|
||||||
|
{ q: "Please take your shoes ___ before you come in.", options: ["on", "off", "up"], answer: 1, explain: "进门前脱鞋,take off = 脱下。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "weekly",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "第 7 周测验",
|
||||||
|
intro: "本周你学了建议与可能性的表达:should 与 ought to、may / might / could、第一条件句、第二条件句、wish,以及短语动词入门。下面 10 题综合检测,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "You look ill. You ___ see a doctor.", options: ["should", "shouldn’t", "mustn’t"], answer: 0, explain: "温和建议用 should。" },
|
||||||
|
{ q: "We ought ___ leave a bit earlier.", options: ["—", "to", "for"], answer: 1, explain: "ought 后必须接 to。" },
|
||||||
|
{ q: "Take an umbrella — it ___ rain this afternoon.", options: ["might", "mustn’t", "can’t"], answer: 0, explain: "猜测可能下雨,用 might。" },
|
||||||
|
{ q: "That ___ be Lily — Lily is on holiday in Sanya.", options: ["can’t", "may", "might"], answer: 0, explain: "人在三亚,不可能是她,用 can’t。" },
|
||||||
|
{ q: "If it ___ tomorrow, we’ll stay at home.", options: ["rains", "will rain", "rained"], answer: 0, explain: "第一条件句 if 从句用一般现在时。" },
|
||||||
|
{ q: "If I ___ a bird, I would fly to you.", options: ["am", "were", "will be"], answer: 1, explain: "第二条件句,想象的情况用 were。" },
|
||||||
|
{ q: "What would you do if you ___ a wallet in the street?", options: ["found", "find", "will find"], answer: 0, explain: "主句 would → if 从句用过去时 found。" },
|
||||||
|
{ q: "I’m so busy. I wish I ___ more free time.", options: ["had", "have", "will have"], answer: 0, explain: "wish 后动词退一步成过去时 had。" },
|
||||||
|
{ q: "I can’t ski at all. I wish I ___ .", options: ["can", "may", "could"], answer: 2, explain: "wish 后表能力用 could。" },
|
||||||
|
{ q: "Which sentence is correct?", options: ["Turn off it.", "Turn it off.", "Turn it off it."], answer: 1, explain: "可分短语动词的代词宾语放中间。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,375 @@
|
|||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 第 8 周:B1 进阶 —— 被动语态(现在/过去)、间接引语(陈述/疑问/命令)、定语从句(限定性/非限定性)
|
||||||
|
// 全部讲解、例句、练习、测验均为原创,仅使用语法主题名称。
|
||||||
|
|
||||||
|
export const week08: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "The passive: present and past",
|
||||||
|
goal: "掌握 am/is/are + 过去分词 与 was/were + 过去分词 的基本结构,能把主动句改成被动句。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Active and passive ideas",
|
||||||
|
zh: "主动句的主语做动作,被动句的主语承受动作。",
|
||||||
|
body: "Most English sentences are active: the subject does the action, as in “My dad washes the car.” A passive sentence turns the idea around. The thing that receives the action moves to the front and becomes the subject: “The car is washed by my dad.” The event is the same, but the focus changes. We use the passive when the result, or the thing itself, is more interesting than who does it.",
|
||||||
|
structure: {
|
||||||
|
cols: ["voice", "subject", "example"],
|
||||||
|
rows: [
|
||||||
|
["active", "the doer", "My dad washes the car."],
|
||||||
|
["passive", "the receiver", "The car is washed by my dad."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Active: My mum makes the cakes. → Passive: The cakes are made by my mum."],
|
||||||
|
note: "Only verbs that take an object can usually become passive. “She sleeps” has no object, so it has no passive form.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The present passive: am / is / are + past participle",
|
||||||
|
zh: "现在时被动 = be 的现在式 + 过去分词,be 随新主语变化。",
|
||||||
|
body: "The present passive uses a form of “be” plus the past participle of the main verb. Choose am, is, or are by looking at the new subject. “The room” is single, so we say “The room is cleaned every day.” “The rooms” is plural, so we say “The rooms are cleaned every day.” This form talks about regular actions or general truths. The past participle is the third verb form: clean–cleaned–cleaned, write–wrote–written.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Subject", "be", "past participle", "Example"],
|
||||||
|
rows: [
|
||||||
|
["single", "is", "cleaned", "The room is cleaned daily."],
|
||||||
|
["plural", "are", "written", "The signs are written in red."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["English is spoken in this shop.", "These bikes are made in our town."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The past passive: was / were + past participle",
|
||||||
|
zh: "过去时被动 = was(单数)/ were(复数)+ 过去分词。",
|
||||||
|
body: "For finished past events we use “was” (single subject) or “were” (plural subject) plus the past participle. “The window was broken last night.” “The keys were found this morning.” Time words such as “last night” or “in 2010” often tell us the action is finished. Everything else stays the same as the present passive: only the form of “be” changes, and the main verb stays a past participle.",
|
||||||
|
examples: ["The match was played on Saturday.", "Two songs were sung at the party."],
|
||||||
|
note: "“I / he / she / it” take was; “you / we / they” take were — exactly like the normal past of “be”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Negatives and questions",
|
||||||
|
zh: "否定在 be 后加 not;疑问把 be 提到句首,主动词不动。",
|
||||||
|
body: "To make a negative, put “not” after the form of “be”: “The letter was not sent.” Short forms work too: isn’t, aren’t, wasn’t, weren’t. For questions, move the form of “be” to the front: “Is the room cleaned every day?” “Were the keys found?” Notice that the main verb never moves — it stays as a past participle at the back of the sentence.",
|
||||||
|
examples: ["Dinner isn’t served before six.", "Was the homework collected yesterday?"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "The rooms ___ cleaned every day.", options: ["is", "are", "am"], answer: 1, explain: "rooms 复数 → are。" },
|
||||||
|
{ q: "My phone ___ made in China.", options: ["is", "are", "be"], answer: 0, explain: "phone 单数 → is。" },
|
||||||
|
{ q: "The windows ___ broken last night.", options: ["was", "were", "is"], answer: 1, explain: "windows 复数 + 过去 → were。" },
|
||||||
|
{ q: "The letter ___ sent yesterday.", options: ["isn’t", "wasn’t", "weren’t"], answer: 1, explain: "letter 单数 + 过去否定 → wasn’t。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "English ___ spoken in many countries.", options: ["is", "are", "am"], answer: 0, explain: "English 视为单数 → is。" },
|
||||||
|
{ q: "These photos ___ taken by my aunt.", options: ["was", "were", "is"], answer: 1, explain: "photos 复数 → were。" },
|
||||||
|
{ q: "___ the room cleaned every day?", options: ["Is", "Are", "Do"], answer: 0, explain: "room 单数,疑问用 Is。" },
|
||||||
|
{ q: "The cars ___ repaired last week.", options: ["are", "were", "is"], answer: 1, explain: "cars 复数 + 过去 → were。" },
|
||||||
|
{ q: "The homework ___ finished yet.", options: ["isn’t", "aren’t", "weren’t"], answer: 0, explain: "homework 不可数,单数 → isn’t。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "The passive: “by” and when to use it",
|
||||||
|
goal: "学会用 by 短语补充施动者,并判断什么时候该用被动语态。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Naming the doer with “by”",
|
||||||
|
zh: "想说明动作是谁做的,就在被动动词后加 by + 施动者。",
|
||||||
|
body: "Sometimes we want to say who did the action. We add a “by” phrase after the passive verb: “The song was written by my sister.” The “by” phrase comes at the end, and it is usually not the main news. If the doer is a person we know, naming them makes the sentence complete; if the doer is unimportant, we can simply leave the phrase out.",
|
||||||
|
structure: {
|
||||||
|
cols: ["form", "example"],
|
||||||
|
rows: [
|
||||||
|
["be + past participle", "The song was written."],
|
||||||
|
["+ by + doer", "The song was written by my sister."],
|
||||||
|
["no doer", "The song was written in 2020."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["The goal was scored by our captain.", "This photo was taken by my grandpa."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Leaving the doer out",
|
||||||
|
zh: "不知道、很明显或不重要谁做的,就不用 by 短语。",
|
||||||
|
body: "Very often a passive sentence has no “by” phrase at all. We drop the doer when we do not know who acted (“My bike was stolen”), when it is obvious (“The rubbish is collected every Friday” — by the cleaners, of course), or when it simply does not matter. Leaving the doer out is one of the biggest reasons we choose the passive over the active voice.",
|
||||||
|
examples: ["My wallet was lost on the bus.", "The emails are answered quickly."],
|
||||||
|
note: "Do not add “by somebody” or “by people” just to fill the gap — it adds nothing. Leave it out.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "When to choose the passive",
|
||||||
|
zh: "重点在事情本身、结果或规定时,用被动更自然。",
|
||||||
|
body: "Choose the passive when the action or its result is the news, not the doer. News reports love it: “A new bridge was opened yesterday.” We also use it to be polite or vague, so nobody is blamed directly: “A mistake was made.” In rules and instructions the passive sounds neutral and fair: “Mobile phones are not allowed in class.”",
|
||||||
|
examples: ["The winner will be announced on Friday.", "These seats are reserved for teachers."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Word order and common mistakes",
|
||||||
|
zh: "被动 = 主语 + be + 过去分词,两个部分缺一不可。",
|
||||||
|
body: "Keep the order: subject + be + past participle + (by ...). Two mistakes are very common. First, forgetting “be”: “The window broken” is wrong — say “The window was broken”. Second, using the wrong verb form: “was break” and “was breaking” are both wrong; only the past participle works after “be”. Check every passive sentence for both “be” and the past participle.",
|
||||||
|
examples: ["Right: The door was locked. / Wrong: The door locked by him."],
|
||||||
|
note: "Some verbs look passive but are not: “The film was exciting” uses an adjective, not a passive verb.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "The book was written ___ my grandfather.", options: ["by", "with", "from"], answer: 0, explain: "被动句引出施动者用 by。" },
|
||||||
|
{ q: "My keys ___ . I can’t find them.", options: ["were lost", "lost", "are lose"], answer: 0, explain: "不知谁弄丢,用被动 were lost。" },
|
||||||
|
{ q: "A new school ___ in our town last year.", options: ["built", "was built", "is build"], answer: 1, explain: "被动需要 be + 过去分词:was built。" },
|
||||||
|
{ q: "Which sentence is correct?", options: ["The cake eaten by Tom.", "The cake was eaten by Tom.", "The cake was eat by Tom."], answer: 1, explain: "被动 = was + 过去分词 eaten。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "The picture was painted ___ a famous artist.", options: ["by", "of", "in"], answer: 0, explain: "引出施动者用 by。" },
|
||||||
|
{ q: "The streets ___ every morning.", options: ["clean", "are cleaned", "cleaned"], answer: 1, explain: "无需说出施动者,用现在被动 are cleaned。" },
|
||||||
|
{ q: "Which is a natural passive sentence?", options: ["Mistake was made.", "A mistake was made.", "A mistake made."], answer: 1, explain: "需要冠词 a 和 be: A mistake was made。" },
|
||||||
|
{ q: "The match ___ on TV last night.", options: ["was shown", "showed", "is show"], answer: 0, explain: "比赛被转播,过去被动 was shown。" },
|
||||||
|
{ q: "Which sentence has the correct order?", options: ["By my mum was cooked dinner.", "Dinner was cooked by my mum.", "Dinner cooked by my mum was."], answer: 1, explain: "主语 + was + 过去分词 + by 短语。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Reported speech 1: statements and backshift",
|
||||||
|
goal: "学会转述别人的陈述句,掌握时态后移与代词、时间词的变化。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Direct and reported speech",
|
||||||
|
zh: "直接引语照搬原话加引号;间接引语用自己的句子转述。",
|
||||||
|
body: "When we repeat someone’s exact words, we use direct speech with inverted commas: “I am tired,” said Leo. When we report the same message later, inside our own sentence, we use reported (indirect) speech: Leo said that he was tired. The reporting verb — usually “said” or “told” — introduces the message. We often add “that”, but in everyday speech we can drop it.",
|
||||||
|
examples: ["Direct: “It is raining,” said Anna. → Reported: Anna said (that) it was raining."],
|
||||||
|
note: "Reported speech has no inverted commas and no question mark, even when the original words had them.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Moving the tense back",
|
||||||
|
zh: "转述时,引语里的动词通常往过去退一步(时态后移)。",
|
||||||
|
body: "Because we usually report words some time after they were spoken, the verb inside the message moves one step into the past. Present simple becomes past simple: “I live in Beijing” → he said he lived in Beijing. Present continuous becomes past continuous: “I am reading” → she said she was reading. Past simple often becomes past perfect: “I lost my pen” → he said he had lost his pen.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Direct", "Reported", "Example"],
|
||||||
|
rows: [
|
||||||
|
["present simple", "past simple", "“I play” → he said he played"],
|
||||||
|
["present continuous", "past continuous", "“I am cooking” → she said she was cooking"],
|
||||||
|
["past simple", "past perfect", "“I saw it” → he said he had seen it"],
|
||||||
|
["will", "would", "“I will call” → she said she would call"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
note: "If the reporting verb is present (“He says …”), the tense inside does not change: He says he is busy.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Changing pronouns and time words",
|
||||||
|
zh: "代词要换成转述者的视角,时间地点词也要跟着移动。",
|
||||||
|
body: "Pronouns change to fit the reporter’s point of view. If Mia says “I like my new school”, you report: Mia said she liked her new school. Time and place words shift too: “today” becomes “that day”, “tomorrow” becomes “the next day”, “yesterday” becomes “the day before”, and “here” becomes “there”. These small changes keep the message honest about when and where things happen.",
|
||||||
|
examples: ["“I will meet you here tomorrow,” he said. → He said he would meet me there the next day."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "“say” and “tell”",
|
||||||
|
zh: "say 直接接内容;tell 后面必须先跟听话人。",
|
||||||
|
body: "Both “say” and “tell” report speech, but they behave differently. “Say” can stand alone or take “that”: She said (that) she was busy. “Tell” must have a listener right after it: She told me (that) she was busy. You cannot say “she told that”. Remember the pattern: tell + person, say + message. For commands and requests, covered next lesson, “tell” is the natural choice.",
|
||||||
|
examples: ["He said he was hungry.", "He told us he was hungry."],
|
||||||
|
note: "Never write “He told to me”. The person follows “tell” directly, with no “to”.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "“I am happy,” said Tom. → Tom said that he ___ happy.", options: ["is", "was", "were"], answer: 1, explain: "时态后移:am → was。" },
|
||||||
|
{ q: "“We play chess,” said the boys. → They said they ___ chess.", options: ["play", "played", "playing"], answer: 1, explain: "一般现在 → 一般过去:played。" },
|
||||||
|
{ q: "She said ___ was ill.", options: ["she", "her", "hers"], answer: 0, explain: "转述里主语用主格 she。" },
|
||||||
|
{ q: "“I will help you,” she told me. → She told me she ___ help me.", options: ["will", "would", "can"], answer: 1, explain: "will → would;tell 后接听话人 me。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "“It is cold,” he said. → He said it ___ cold.", options: ["is", "was", "be"], answer: 1, explain: "is → was。" },
|
||||||
|
{ q: "Which uses “tell” correctly?", options: ["He told that he was late.", "He told me that he was late.", "He told me he is late."], answer: 1, explain: "tell + 人 + that;且时态要后移。" },
|
||||||
|
{ q: "“I saw a film yesterday,” she said. → She said she had seen a film ___.", options: ["yesterday", "the day before", "tomorrow"], answer: 1, explain: "yesterday → the day before。" },
|
||||||
|
{ q: "“We are studying,” they said. → They said they ___.", options: ["are studying", "were studying", "study"], answer: 1, explain: "现在进行 → 过去进行。" },
|
||||||
|
{ q: "“I will call tomorrow,” he said. → He said he would call ___.", options: ["tomorrow", "the next day", "today"], answer: 1, explain: "tomorrow → the next day。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Reported speech 2: questions and commands",
|
||||||
|
goal: "学会转述疑问句(含 yes/no 问句)与命令、请求。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Reporting questions: keep it flat",
|
||||||
|
zh: "转述疑问句时语序变平(像陈述句),去掉 do/does/did。",
|
||||||
|
body: "A direct question has question word order: “Where do you live?” When we report it, the word order becomes flat, like a normal sentence, and we drop “do / does / did”: She asked me where I lived. The tense still moves back, and the question mark disappears. Never keep the inverted order in reported questions — “she asked where did I live” is a very common error.",
|
||||||
|
examples: ["“Where do you work?” → She asked me where I worked."],
|
||||||
|
note: "Reported questions end with a full stop, not a question mark: She asked where I lived.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Wh- questions",
|
||||||
|
zh: "特殊疑问句保留原来的疑问词当连接词,动词移到句尾。",
|
||||||
|
body: "If the question begins with a question word — what, where, when, why, who, how — keep that word as the connector. “What is your name?” → He asked what my name was. “Why are you crying?” → Mum asked why I was crying. The question word joins the two parts of the sentence, and the verb (or its subject) settles into statement order after it.",
|
||||||
|
examples: ["“When does the bus leave?” → She asked when the bus left."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Yes/no questions with “if” or “whether”",
|
||||||
|
zh: "一般疑问句没有疑问词,用 if(或 whether)连接。",
|
||||||
|
body: "Questions that expect “yes” or “no” have no question word, so we connect them with “if” (or the more formal “whether”). “Do you like tea?” → She asked if I liked tea. “Have you finished?” → Dad asked whether I had finished. Again there is no “do / does / did”, no question mark, and the tense moves back one step, just like reported statements.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Direct question", "Reported"],
|
||||||
|
rows: [
|
||||||
|
["“Do you swim?”", "He asked if I swam."],
|
||||||
|
["“Is she at home?”", "She asked if he was at home."],
|
||||||
|
["“Have you eaten?”", "Mum asked whether I had eaten."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["“Can you help me?” → He asked if I could help him."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Reporting commands and requests",
|
||||||
|
zh: "命令和请求用 tell/ask + 人 + to + 动词原形。",
|
||||||
|
body: "For orders and requests we use “tell” or “ask” + person + to + base verb. “Close the door,” said Mum → Mum told me to close the door. “Please help me,” said Anna → Anna asked me to help her. For negative commands, put “not” before “to”: “Don’t shout” → The teacher told us not to shout. “Ask” sounds softer and more polite than “tell”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["Direct", "Reported"],
|
||||||
|
rows: [
|
||||||
|
["“Wait here.”", "He told me to wait there."],
|
||||||
|
["“Please sit down.”", "She asked me to sit down."],
|
||||||
|
["“Don’t run.”", "He told us not to run."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
note: "Never say “He told me that to close”. Commands use “to + verb”, with no “that”.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "“Where do you live?” she asked me. → She asked me where I ___.", options: ["live", "lived", "do live"], answer: 1, explain: "去掉 do,时态后移:lived。" },
|
||||||
|
{ q: "“Are you tired?” he asked. → He asked ___ I was tired.", options: ["what", "if", "that"], answer: 1, explain: "yes/no 问句用 if 连接。" },
|
||||||
|
{ q: "“Open the window,” said Dad. → Dad told me ___ the window.", options: ["open", "to open", "opening"], answer: 1, explain: "命令用 to + 动词原形。" },
|
||||||
|
{ q: "“Don’t run,” said the teacher. → The teacher told us ___.", options: ["not to run", "to not run", "don’t run"], answer: 0, explain: "否定命令:not + to run。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "“What is this?” he asked. → He asked what ___.", options: ["is this", "this was", "was this"], answer: 1, explain: "平语序 + 时态后移:this was。" },
|
||||||
|
{ q: "“Do you speak French?” she asked him. → She asked him ___ he spoke French.", options: ["that", "if", "what"], answer: 1, explain: "一般疑问句用 if。" },
|
||||||
|
{ q: "“Sit down,” said the doctor. → The doctor told me ___.", options: ["sit down", "to sit down", "sitting down"], answer: 1, explain: "tell + 人 + to + 原形。" },
|
||||||
|
{ q: "“Don’t be late,” said Mum. → Mum told me ___ late.", options: ["to not be", "not to be", "don’t be"], answer: 1, explain: "not 放在 to 前:not to be。" },
|
||||||
|
{ q: "“Why are you laughing?” she asked. → She asked me why ___.", options: ["was I laughing", "I was laughing", "do I laugh"], answer: 1, explain: "保留疑问词,后面用平语序。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Defining relative clauses (who / which / that / whose)",
|
||||||
|
goal: "用限定性定语从句说明“哪一个”,掌握 who/which/that/whose 的选择与省略。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "What a defining clause does",
|
||||||
|
zh: "限定性从句给出必要信息,说明到底是哪一个,不用逗号。",
|
||||||
|
body: "A defining relative clause tells us exactly which person or thing we mean. It is necessary information — take it away and the sentence no longer identifies the right one. “The boy who sits next to me is called Sam.” Without the clause, we do not know which boy. Defining clauses are not separated by commas, and in speech there is no pause before them.",
|
||||||
|
examples: ["The shop that sells noodles is closed today."],
|
||||||
|
note: "If removing the clause changes which person or thing we mean, the clause is defining — and it needs no commas.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "who, which and that",
|
||||||
|
zh: "人用 who,物用 which,that 两者皆可(口语常用)。",
|
||||||
|
body: "Use “who” for people, “which” for things and animals, and “that” for either. “The girl who won the race is my cousin.” “This is the phone which I want.” In defining clauses “that” can replace who or which, and in everyday speech it is very common: “the phone that I want”. Many learners simply use “that” and stay safe in most sentences.",
|
||||||
|
structure: {
|
||||||
|
cols: ["refers to", "relative pronoun", "example"],
|
||||||
|
rows: [
|
||||||
|
["people", "who / that", "the man who called"],
|
||||||
|
["things / animals", "which / that", "the dog which barked"],
|
||||||
|
["possession", "whose", "the boy whose bike was stolen"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["The letter that arrived today is from my uncle."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "whose for possession",
|
||||||
|
zh: "从句里表示“谁的”所属关系时,用 whose。",
|
||||||
|
body: "When the clause shows that something belongs to the person or thing, we use “whose”. It replaces “his / her / their” inside the clause. “That’s the girl whose brother plays in our band.” (= her brother) “I met a man whose cat can open doors.” (= his cat) “Whose” is used mostly for people; for things, careful writers sometimes prefer “of which”, but “whose” is fine in daily English.",
|
||||||
|
examples: ["The student whose phone rang left the room."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Leaving out who / which / that",
|
||||||
|
zh: "关系词在从句中做宾语时可省略,做主语时不能省。",
|
||||||
|
body: "When the relative pronoun is the object of its clause, you may drop it entirely: “The book (that) I read was exciting.” “The man (who) you met is a chef.” But when it is the subject, it must stay: “The boy who called is my cousin” — never “The boy called is my cousin”. A quick test: if a noun or pronoun comes right after the relative word, dropping is usually allowed.",
|
||||||
|
examples: ["The film (that) we saw was long.", "The girl who sings is here. (cannot drop)"],
|
||||||
|
note: "“whose” can never be dropped: “the boy whose bike…” must keep whose.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "The woman ___ called is my aunt.", options: ["who", "which", "whose"], answer: 0, explain: "指人且做从句主语 → who。" },
|
||||||
|
{ q: "This is the cake ___ Mum made.", options: ["who", "which", "whose"], answer: 1, explain: "指物、做宾语 → which(that 也可)。" },
|
||||||
|
{ q: "I know a boy ___ sister is a pilot.", options: ["who", "that", "whose"], answer: 2, explain: "表示所属“他的姐姐”→ whose。" },
|
||||||
|
{ q: "Which sentence can drop the relative pronoun?", options: ["The dog that bit me ran away.", "The film that we saw was long.", "The girl that sings is here."], answer: 1, explain: "that 后接 we,是宾语,可省略。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "The students ___ passed were happy.", options: ["which", "who", "whose"], answer: 1, explain: "指人做主语 → who。" },
|
||||||
|
{ q: "Where is the pen ___ was on the desk?", options: ["who", "which", "whose"], answer: 1, explain: "指物做主语,用 which,不可省。" },
|
||||||
|
{ q: "That’s the man ___ car was stolen.", options: ["who", "that", "whose"], answer: 2, explain: "“他的车”表所属 → whose。" },
|
||||||
|
{ q: "The film ___ we watched was scary.", options: ["who", "whose", "that"], answer: 2, explain: "指物做宾语,用 that(可省)。" },
|
||||||
|
{ q: "Which is a defining clause with NO commas?", options: ["My mum, who is kind, cooks well.", "The girl who sits behind me is new.", "Tom, who is ten, likes cats."], answer: 1, explain: "限定性从句不加逗号。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Non-defining relative clauses",
|
||||||
|
goal: "用非限定性定语从句补充额外信息,掌握逗号规则与 that 的禁用。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Adding extra information",
|
||||||
|
zh: "非限定性从句补充“顺便一提”的信息,删掉句子仍完整。",
|
||||||
|
body: "A non-defining relative clause adds bonus information about a person or thing we have already identified. Take it away and the sentence still makes full sense: “My brother, who lives in Canada, is a doctor.” We already know who “my brother” is; the clause just adds colour. Names, family words with “my”, and unique things like “the sun” very often take this kind of clause.",
|
||||||
|
examples: ["Our school, which is very old, has a huge library."],
|
||||||
|
note: "If the clause is only extra information, not needed to identify the noun, it is non-defining.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Commas are compulsory",
|
||||||
|
zh: "非限定性从句必须用逗号括起来:前面一个,后面一个。",
|
||||||
|
body: "Non-defining clauses must be wrapped in commas — one before, and one after if the clause sits in the middle: “My teacher, who is from Italy, loves opera.” If the clause comes at the end, a single comma leads it in: “I thanked Mr Lee, who had helped me all year.” The commas work like brackets; they tell the reader that the information is extra and removable.",
|
||||||
|
examples: ["Beijing, which is the capital, is very big."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "No “that”, and no dropping",
|
||||||
|
zh: "非限定性从句不能用 that,关系词也绝不能省略。",
|
||||||
|
body: "Two strict rules separate non-defining clauses from defining ones. First, you cannot use “that” — only “who” (people) or “which” (things): “My bike, which is very old, still works.” Never “my bike, that is very old”. Second, you can never drop the relative pronoun, even when it is the object: “The cake, which Mum baked, was huge.” The “which” must stay in place.",
|
||||||
|
structure: {
|
||||||
|
cols: ["rule", "right", "wrong"],
|
||||||
|
rows: [
|
||||||
|
["no “that”", "My dad, who is tall, …", "My dad, that is tall, …"],
|
||||||
|
["no dropping", "The cake, which she baked, …", "The cake, she baked, …"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["Ms Wang, who teaches us maths, is very patient."],
|
||||||
|
note: "In non-defining clauses “which” can refer to the whole previous sentence: “He passed, which made us all happy.”",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Comparing the two clause types",
|
||||||
|
zh: "限定性从句无逗号、限定范围;非限定性从句有逗号、补充全体。",
|
||||||
|
body: "Put the two side by side. A defining clause has no commas and tells us which ones: “The students who studied passed.” (only some students studied). A non-defining clause has commas and comments on all of them: “The students, who had studied, passed.” (all the students, and they had studied). Commas can change the meaning, so first decide whether your information is necessary or just extra.",
|
||||||
|
structure: {
|
||||||
|
cols: ["type", "commas", "example"],
|
||||||
|
rows: [
|
||||||
|
["defining", "no", "The boy who called is Sam."],
|
||||||
|
["non-defining", "yes", "My brother, who is ten, is here."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["My sisters, who live abroad, visit every summer. (all my sisters)"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "My dad, ___ is 40, runs fast.", options: ["that", "who", "whose"], answer: 1, explain: "非限定性从句指人不能用 that,用 who。" },
|
||||||
|
{ q: "Which punctuation is correct?", options: ["My sister who is a nurse lives here.", "My sister, who is a nurse, lives here.", "My sister, who is a nurse lives here."], answer: 1, explain: "非限定性从句前后都要逗号。" },
|
||||||
|
{ q: "Our house, ___ is very old, has a big garden.", options: ["that", "which", "who"], answer: 1, explain: "指物的非限定性从句用 which。" },
|
||||||
|
{ q: "In non-defining clauses, the relative pronoun ___ be dropped.", options: ["can", "cannot", "must"], answer: 1, explain: "非限定性从句的关系词绝不能省略。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "Mount Everest, ___ is very high, attracts climbers.", options: ["that", "who", "which"], answer: 2, explain: "非限定性、指物 → which。" },
|
||||||
|
{ q: "Which sentence is correct?", options: ["Mr Wu, that teaches maths, is funny.", "Mr Wu, who teaches maths, is funny.", "Mr Wu who teaches maths, is funny."], answer: 1, explain: "非限定性指人用 who,且要有逗号。" },
|
||||||
|
{ q: "Non-defining clauses give ___ information.", options: ["necessary", "extra", "no"], answer: 1, explain: "非限定性从句提供额外信息。" },
|
||||||
|
{ q: "My cat, ___ is black, sleeps a lot.", options: ["who", "which", "whose"], answer: 1, explain: "指物(动物)的非限定性从句用 which。" },
|
||||||
|
{ q: "Which sentence uses commas correctly?", options: ["The pen, which is red, is mine.", "The pen, which is red is mine.", "The pen which is red, is mine."], answer: 0, explain: "从句前后各一个逗号。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "weekly",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "第 8 周测验",
|
||||||
|
intro: "本周你学了被动语态、间接引语和定语从句。下面 10 题综合检测本周内容,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "The letters ___ every morning.", options: ["are delivered", "deliver", "delivered"], answer: 0, explain: "信件被投递,现在被动 are delivered。" },
|
||||||
|
{ q: "My phone ___ yesterday.", options: ["was stolen", "stolen", "is stolen"], answer: 0, explain: "过去被动:was stolen。" },
|
||||||
|
{ q: "The song was sung ___ a famous star.", options: ["by", "with", "from"], answer: 0, explain: "引出施动者用 by。" },
|
||||||
|
{ q: "“I am busy,” she said. → She said she ___ busy.", options: ["is", "was", "be"], answer: 1, explain: "时态后移:am → was。" },
|
||||||
|
{ q: "He asked me ___ I liked football.", options: ["what", "if", "that"], answer: 1, explain: "yes/no 问句用 if 连接。" },
|
||||||
|
{ q: "“Close the door,” he said. → He told me ___ the door.", options: ["to close", "close", "closing"], answer: 0, explain: "命令用 tell + 人 + to + 原形。" },
|
||||||
|
{ q: "The girl ___ lives upstairs is friendly.", options: ["which", "who", "whose"], answer: 1, explain: "指人做主语 → who。" },
|
||||||
|
{ q: "That’s the boy ___ dad is a chef.", options: ["who", "that", "whose"], answer: 2, explain: "表所属“他的爸爸”→ whose。" },
|
||||||
|
{ q: "My uncle, ___ lives in Paris, is visiting.", options: ["that", "who", "which"], answer: 1, explain: "非限定性从句指人不能用 that,用 who。" },
|
||||||
|
{ q: "Which sentence is correct?", options: ["The room cleaned yesterday.", "The room was cleaned yesterday.", "The room is clean yesterday."], answer: 1, explain: "被动 = was + 过去分词 cleaned。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,361 @@
|
|||||||
|
import type { SyllabusEntry } from "./types";
|
||||||
|
|
||||||
|
// 第 9 周:B1 进阶 —— 推测性情态动词、反意疑问句、动名词与不定式、冠词深入、连词、连接与顺序词
|
||||||
|
// 全部讲解、例句、练习、测验均为原创,仅使用语法主题名称。
|
||||||
|
|
||||||
|
export const week09: SyllabusEntry[] = [
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Modals of deduction (must be / can’t be / might be)",
|
||||||
|
goal: "用 must / can't / might + be 对现在情况做有把握程度的推测。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Guessing with modals",
|
||||||
|
zh: "不确定时,用情态动词 + be 表达“多半是/不可能是/也许是”。",
|
||||||
|
body: "Sometimes we are not certain about something, so we make a careful guess. English uses special modal verbs for this: “must”, “can’t”, “might” (and “could” or “may”). We add “be” plus an adjective or a noun: “He must be at home.” These words do not describe facts; they show how strong our evidence feels, from near-certain at one end to only possible at the other.",
|
||||||
|
structure: {
|
||||||
|
cols: ["strength", "modal", "example"],
|
||||||
|
rows: [
|
||||||
|
["almost sure (yes)", "must be", "He must be at home."],
|
||||||
|
["almost sure (no)", "can’t be", "It can’t be true."],
|
||||||
|
["possible", "might / could / may be", "She might be right."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["You’ve just run a race — you must be thirsty!"],
|
||||||
|
note: "These modals are followed by the base form “be”, never “is” or “are”: “He must be tired”, not “must is tired”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "must be: near-certain yes",
|
||||||
|
zh: "证据充分、几乎肯定的正面推测用 must be。",
|
||||||
|
body: "Use “must be” when the evidence points strongly one way and you feel almost sure. You see a coat by the door and hear voices: “Dad must be home.” You meet someone after a twelve-hour flight: “You must be tired!” It is a confident positive guess about the present. For a guess about the past, the form changes to “must have”: “He must have forgotten our meeting.”",
|
||||||
|
examples: ["She speaks five languages. She must be very clever."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "can’t be: near-certain no",
|
||||||
|
zh: "几乎不可能的负面推测用 can't be,不要用 mustn't be。",
|
||||||
|
body: "“Can’t be” is the opposite of “must be”: the evidence makes something almost impossible. “She can’t be at school — it’s Sunday!” “That man can’t be her father; he looks younger than she does.” Notice that we do not say “mustn’t be” with this meaning. “Mustn’t” expresses prohibition (“You mustn’t smoke here”), not a negative guess. Mixing them up is a classic learner trap.",
|
||||||
|
examples: ["You ate a huge lunch an hour ago. You can’t be hungry already!"],
|
||||||
|
note: "For a near-certain “no” about the past, use “can’t have”: “He can’t have left — his bag is still here.”",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "might / could / may be: possible",
|
||||||
|
zh: "把握不大、五五开时用 might / could / may be。",
|
||||||
|
body: "When you are not sure either way — perhaps fifty-fifty — use “might”, “could”, or “may”. “Take an umbrella; it might rain.” “Where’s Sam?” “He could be in the library.” “May” is a little more formal than “might”. All three express possibility, not certainty, and they are roughly the same strength. For a possibility in the past, say “might have”: “She might have missed the bus.”",
|
||||||
|
examples: ["Knock first — the baby might be sleeping."],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She has worked for 12 hours. She ___ exhausted.", options: ["must be", "can’t be", "might be"], answer: 0, explain: "证据强,几乎肯定 → must be。" },
|
||||||
|
{ q: "He ___ be at work — his car isn’t there.", options: ["must", "can’t", "might"], answer: 1, explain: "几乎不可能 → can’t be。" },
|
||||||
|
{ q: "I’m not sure, but she ___ be in the garden.", options: ["must", "can’t", "might"], answer: 2, explain: "把握不大 → might be。" },
|
||||||
|
{ q: "You ___ smoke here. It is forbidden.", options: ["mustn’t", "might", "could"], answer: 0, explain: "表示“禁止”用 mustn’t,不是推测。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "The lights are on. Someone ___ be home.", options: ["must", "can’t", "mustn’t"], answer: 0, explain: "灯亮着,几乎肯定有人 → must。" },
|
||||||
|
{ q: "She ___ be a baby — she’s forty!", options: ["must", "can’t", "might"], answer: 1, explain: "四十岁不可能是婴儿 → can’t。" },
|
||||||
|
{ q: "I’m not sure where he is. He ___ be at the shop.", options: ["must", "can’t", "could"], answer: 2, explain: "不确定 → could(也许)。" },
|
||||||
|
{ q: "You ___ park here; there’s a “no parking” sign.", options: ["mustn’t", "must", "could"], answer: 0, explain: "禁止停车 → mustn’t。" },
|
||||||
|
{ q: "“He’s been running.” “He ___ be tired.”", options: ["must", "can’t", "may"], answer: 0, explain: "跑完步几乎肯定累 → must。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Question tags",
|
||||||
|
goal: "掌握反意疑问句的“前肯后否、前否后肯”规则与常见特殊形式。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "What tags do",
|
||||||
|
zh: "反意疑问句 = 陈述句 + 句尾小问句,用来确认或征求同意。",
|
||||||
|
body: "A question tag is a tiny question glued to the end of a sentence: “You like tea, don’t you?” We use tags to check information or to invite agreement. The tag always contains an auxiliary verb (be, do, have, will, can …) and a pronoun matching the subject. In speech, a falling tone asks for agreement, while a rising tone asks a real question you are unsure about.",
|
||||||
|
examples: ["It’s a lovely day, isn’t it?"],
|
||||||
|
note: "The tag always uses a pronoun subject, never a noun: “Your sister is kind, isn’t she?”, not “isn’t your sister”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The golden rule: opposite polarity",
|
||||||
|
zh: "前肯后否、前否后肯,像跷跷板一样相反。",
|
||||||
|
body: "The main rule is simple: a positive sentence takes a negative tag, and a negative sentence takes a positive tag. “She is kind, isn’t she?” “You don’t eat meat, do you?” “They have finished, haven’t they?” “He can’t swim, can he?” Think of it as a seesaw: if one side is up, the other is down. Get this habit right and most tags become automatic.",
|
||||||
|
structure: {
|
||||||
|
cols: ["statement", "tag", "example"],
|
||||||
|
rows: [
|
||||||
|
["positive", "negative tag", "It’s cold, isn’t it?"],
|
||||||
|
["negative", "positive tag", "You aren’t busy, are you?"],
|
||||||
|
["with will", "won’t", "She’ll come, won’t she?"],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["They won’t mind, will they?"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Tags with “do” and with “be”",
|
||||||
|
zh: "句中无 be/助动词时,疑问尾巴借用 do/does/did。",
|
||||||
|
body: "If the sentence has no visible helper, the tag borrows “do / does / did”. “You live here, don’t you?” “She plays tennis, doesn’t she?” “They left early, didn’t they?” If the sentence already has “be”, “have”, or a modal, the tag repeats that very word: “He is late, isn’t he?” “You can drive, can’t you?” Never mix the two systems in one tag.",
|
||||||
|
examples: ["Your brother works in a bank, doesn’t he?"],
|
||||||
|
note: "Match the tense in the tag: present → don’t / doesn’t, past → didn’t.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Special cases: I am, imperatives, let’s",
|
||||||
|
zh: "几个特殊尾巴要记牢:aren't I、will you、shall we。",
|
||||||
|
body: "A few tags are irregular and must be memorised. “I am right” takes “aren’t I?” — there is no “amn’t I”. Negative words like “never” or “hardly” make a sentence negative, so the tag is positive: “He never calls, does he?” With commands we often tag “will you?”: “Close the door, will you?” And after “let’s” we use “shall we?”: “Let’s go, shall we?”",
|
||||||
|
examples: ["I’m your best friend, aren’t I?", "Don’t be late, will you?"],
|
||||||
|
note: "Sentences with never, hardly, seldom count as negative, so their tags are positive.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "She is your teacher, ___ ?", options: ["isn’t she", "is she", "doesn’t she"], answer: 0, explain: "前肯后否,重复 is:isn’t she。" },
|
||||||
|
{ q: "You don’t like fish, ___ ?", options: ["don’t you", "do you", "are you"], answer: 1, explain: "前否后肯:do you。" },
|
||||||
|
{ q: "They play football, ___ ?", options: ["do they", "don’t they", "aren’t they"], answer: 1, explain: "无 be/助动词,借 do,前肯后否。" },
|
||||||
|
{ q: "I am late, ___ ?", options: ["amn’t I", "aren’t I", "isn’t I"], answer: 1, explain: "I am 的特殊尾巴是 aren’t I。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "He can swim, ___ ?", options: ["can he", "can’t he", "doesn’t he"], answer: 1, explain: "前肯后否,重复 can:can’t he。" },
|
||||||
|
{ q: "She lives in London, ___ ?", options: ["doesn’t she", "isn’t she", "does she"], answer: 0, explain: "一般现在时借 does,前肯后否。" },
|
||||||
|
{ q: "It was a good film, ___ ?", options: ["wasn’t it", "didn’t it", "isn’t it"], answer: 0, explain: "重复 was,前肯后否。" },
|
||||||
|
{ q: "He never eats meat, ___ ?", options: ["doesn’t he", "does he", "is he"], answer: 1, explain: "never 使句子含否定,尾巴用肯定 does he。" },
|
||||||
|
{ q: "Let’s have a break, ___ ?", options: ["will we", "shall we", "don’t we"], answer: 1, explain: "let’s 的尾巴固定用 shall we。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Verb patterns: gerund vs infinitive",
|
||||||
|
goal: "区分动词后接动名词(verb-ing)还是不定式(to + 动词)的常见搭配。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Two verb shapes after verbs",
|
||||||
|
zh: "一个动词接另一个动词时,后者要么用 -ing,要么用 to + 原形。",
|
||||||
|
body: "When one verb follows another, the second verb takes one of two shapes: the gerund (verb + -ing) or the infinitive (to + verb). “I enjoy reading.” but “I want to read.” The choice depends on the first verb — there is no single rule of logic, so we learn common verbs in groups. Getting this right is what makes your English start to sound natural.",
|
||||||
|
structure: {
|
||||||
|
cols: ["pattern", "verbs", "example"],
|
||||||
|
rows: [
|
||||||
|
["verb + -ing", "enjoy, finish, mind", "I enjoy cooking."],
|
||||||
|
["verb + to …", "want, decide, hope", "She wants to go."],
|
||||||
|
["both, small difference", "like, love, start", "I like swimming / to swim."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["We finished cleaning the classroom at five."],
|
||||||
|
note: "After prepositions the verb is always -ing: “I’m good at drawing”, “thanks for helping”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Verbs that take the gerund",
|
||||||
|
zh: "enjoy / finish / mind / keep / avoid 等后面只接 -ing。",
|
||||||
|
body: "Some verbs are always followed by verb-ing. Common ones are enjoy, finish, mind, practise, avoid, suggest, and keep. “She finished doing her homework.” “Do you mind opening the window?” “He keeps losing his keys.” The phrase “can’t help” also takes -ing: “I can’t help laughing.” Notice that there is never a “to” between these verbs and the -ing form.",
|
||||||
|
examples: ["I suggest taking the earlier train.", "Would you mind waiting a minute?"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Verbs that take the infinitive",
|
||||||
|
zh: "want / hope / decide / plan / would like 等后面接 to + 动词。",
|
||||||
|
body: "Other verbs are followed by “to + verb”. Very common ones are want, hope, decide, plan, need, would like, and learn. “I want to buy a bike.” “She decided to stay home.” “We would like to invite you to the party.” After adjectives we also use the infinitive: “It is easy to learn.” “I’m happy to help you with it.”",
|
||||||
|
examples: ["They plan to visit the museum on Sunday."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Tricky verbs: like, stop, remember",
|
||||||
|
zh: "like/love/start 两种都行;stop、remember 两种意思不同。",
|
||||||
|
body: "A few verbs take both shapes, sometimes with a change of meaning. “Like / love / hate / start” work with either, with little difference: “I like swimming” and “I like to swim”. But “stop” differs: “He stopped smoking” (he quit) versus “He stopped to smoke” (he paused in order to smoke). “Remember to lock the door” means don’t forget the task; “I remember locking it” describes a memory.",
|
||||||
|
examples: ["She started crying / to cry at the sad film."],
|
||||||
|
note: "“stop + -ing” = 停止做某事;“stop + to do” = 停下来去做另一件事。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I enjoy ___ basketball.", options: ["to play", "playing", "play"], answer: 1, explain: "enjoy 后接 -ing:playing。" },
|
||||||
|
{ q: "She decided ___ early.", options: ["leaving", "to leave", "leave"], answer: 1, explain: "decide 后接 to + 动词。" },
|
||||||
|
{ q: "Do you mind ___ the door?", options: ["to open", "opening", "open"], answer: 1, explain: "mind 后接 -ing。" },
|
||||||
|
{ q: "He stopped ___ . (= he no longer smokes)", options: ["to smoke", "smoking", "smoke"], answer: 1, explain: "“戒烟”用 stop + -ing。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "We hope ___ you soon.", options: ["seeing", "to see", "see"], answer: 1, explain: "hope 后接 to + 动词。" },
|
||||||
|
{ q: "He keeps ___ the same mistake.", options: ["to make", "making", "make"], answer: 1, explain: "keep 后接 -ing。" },
|
||||||
|
{ q: "I’d like ___ a question.", options: ["asking", "to ask", "ask"], answer: 1, explain: "would like 后接 to + 动词。" },
|
||||||
|
{ q: "She can’t help ___ at his jokes.", options: ["to laugh", "laughing", "laugh"], answer: 1, explain: "can’t help 后接 -ing。" },
|
||||||
|
{ q: "Remember ___ off the lights before bed.", options: ["turning", "to turn", "turn"], answer: 1, explain: "别忘了要做的任务 → to turn。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Articles in depth (a / an / the / zero article)",
|
||||||
|
goal: "深入掌握冠词:何时用 a/an、the,何时用零冠词。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Recap: a / an / the",
|
||||||
|
zh: "a/an 泛指一个,the 特指或唯一;元音音素前用 an。",
|
||||||
|
body: "Quick reminder: “a / an” introduces one non-specific countable noun (“I saw a bird”); “the” points to something specific or unique (“the bird on our roof”, “the moon”). Use “an” before a vowel sound, even when the letter is a consonant: “an hour”. In this lesson we go further: when do we use no article at all, and how do articles behave with plurals and uncountable nouns?",
|
||||||
|
examples: ["I met a doctor. The doctor was very kind."],
|
||||||
|
note: "It is the sound, not the spelling, that decides a or an: a university, an honest man.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "The zero article",
|
||||||
|
zh: "零冠词:泛指复数/不可数名词、多数地名、三餐、by + 交通。",
|
||||||
|
body: "We use no article (the “zero article”) in several important cases. With plural and uncountable nouns when speaking in general: “Dogs are friendly.” “Water is vital.” With most names: “I live in Beijing.” “She likes Anna.” With meals: “We had breakfast at eight.” With transport after “by”: “by bus”, “by train”. And with school, bed, and home when used for their purpose: “go to school”, “go to bed”, “go home”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["use", "article", "example"],
|
||||||
|
rows: [
|
||||||
|
["one, non-specific", "a / an", "I read a book."],
|
||||||
|
["specific / unique", "the", "the moon, the book you lent me"],
|
||||||
|
["general plural / names", "— (zero)", "Dogs bark. I live in Shanghai."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["She goes to work by bike."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "General vs specific",
|
||||||
|
zh: "同一个名词,泛指不加冠词,特指加 the。",
|
||||||
|
body: "The same noun can be general or specific. General (no article): “I love cats.” (all cats). Specific (the): “The cats next door are noisy.” (particular cats). With uncountable nouns it works the same way: “Coffee keeps me awake.” (coffee in general) versus “The coffee in this cup is cold.” (this particular coffee). Always ask yourself: am I talking about all of it, or one particular amount?",
|
||||||
|
examples: ["Children need sleep. / The children in our class are ten."],
|
||||||
|
note: "“Most children like games.” — no “the”. But “Most of the children in our class…” needs “the”.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Fixed places and exceptions",
|
||||||
|
zh: "go to school/bed/home 无 the;部分国名(the USA)要加 the。",
|
||||||
|
body: "Some places take no article when we use them for their purpose: “go to school” (as a student), “go to hospital” (as a patient), “go to bed”, “go home”. But “go to the bank”, “go to the cinema”, “go to the doctor” keep “the”. Names of countries are usually bare (“France”, “China”), yet plural or compound names take it: “the USA”, “the Netherlands”, “the UK”.",
|
||||||
|
examples: ["My father is in hospital. / I’m going to the bank after school."],
|
||||||
|
note: "Rivers, seas and mountain ranges take “the” (the Yangtze, the Alps); single mountains do not (Mount Tai).",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I go to school by ___ bus.", options: ["a", "the", "— (no article)"], answer: 2, explain: "by + 交通工具用零冠词。" },
|
||||||
|
{ q: "___ dogs are loyal animals.", options: ["A", "The", "—"], answer: 2, explain: "复数名词泛指,零冠词。" },
|
||||||
|
{ q: "She lives in ___ United Kingdom.", options: ["a", "the", "—"], answer: 1, explain: "复合国名加 the。" },
|
||||||
|
{ q: "Let’s have ___ dinner.", options: ["a", "the", "—"], answer: 2, explain: "三餐前用零冠词。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "I love ___ music.", options: ["—", "a", "the"], answer: 0, explain: "不可数名词泛指 → 零冠词。" },
|
||||||
|
{ q: "___ moon is bright tonight.", options: ["A", "The", "An"], answer: 1, explain: "独一无二的事物用 the。" },
|
||||||
|
{ q: "He goes to ___ bed at ten.", options: ["—", "the", "a"], answer: 0, explain: "go to bed 固定零冠词。" },
|
||||||
|
{ q: "We visited ___ France last summer.", options: ["the", "a", "—"], answer: 2, explain: "普通国名前零冠词。" },
|
||||||
|
{ q: "___ coffee in this cup is cold.", options: ["A", "The", "An"], answer: 1, explain: "特指这杯里的咖啡 → the。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Conjunctions: although / because / so / unless",
|
||||||
|
goal: "用 because / so / although / unless 在句内表达原因、结果、让步与条件。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Linking ideas within a sentence",
|
||||||
|
zh: "连词把两个想法连进一个句子,说明它们之间的关系。",
|
||||||
|
body: "Conjunctions join two ideas inside one sentence. Four very useful ones are “because”, “so”, “although”, and “unless”. Each expresses a different relationship: reason, result, contrast, or condition. Choosing the right one tells the listener exactly how the two halves connect. You can usually put the conjunction in the middle of the sentence or at the very start, followed by a comma.",
|
||||||
|
examples: ["I smiled because I was happy."],
|
||||||
|
note: "because 答 “why” 的问题;回答 “Why are you late?” 说 “Because I missed the bus.”,不说 “So …”。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "because and so: reason and result",
|
||||||
|
zh: "because 引原因,so 引结果;一个句子里不要两个都用。",
|
||||||
|
body: "“Because” introduces a reason; “so” introduces a result. “I stayed home because it rained.” (reason) “It rained, so I stayed home.” (result). They are two sides of the same coin. A common mistake is using both in one sentence: “Because it rained, so I stayed home” is wrong in English. Pick just one. “Why?” questions are answered with “because”, never with “so”.",
|
||||||
|
structure: {
|
||||||
|
cols: ["conjunction", "meaning", "example"],
|
||||||
|
rows: [
|
||||||
|
["because", "reason", "I smiled because I was happy."],
|
||||||
|
["so", "result", "I was happy, so I smiled."],
|
||||||
|
["although", "contrast", "Although I was tired, I finished."],
|
||||||
|
["unless", "if not", "Unless you hurry, you’ll be late."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["She was hungry, so she made a sandwich."],
|
||||||
|
note: "so 前面通常有逗号;because 从句放句首时,主句前加逗号。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "although: contrast and surprise",
|
||||||
|
zh: "although(虽然)连接转折,不能和 but 同时出现。",
|
||||||
|
body: "“Although” (or the slightly more informal “though”) joins two ideas that contrast or surprise us. “Although it rained, we had a picnic.” “She passed the exam although she was ill.” No comma is needed when “although” sits in the middle of the sentence. Don’t add “but” in the same sentence: not “although it rained, but we went out”. The single word already carries all the contrast you need.",
|
||||||
|
examples: ["Although he is only ten, he cooks very well."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "unless: “if … not”",
|
||||||
|
zh: "unless = 如果不/除非,本身含否定,别再叠加 not。",
|
||||||
|
body: "“Unless” means “if … not” or “except if”. “You will fail unless you study.” (= if you don’t study) “I won’t go unless you come with me.” Because “unless” already contains the negative idea, don’t add another “not”: “unless you don’t study” is wrong. It is very common in warnings and rules: “No entry unless you have a ticket.”",
|
||||||
|
examples: ["Unless it rains, we’ll play football after school."],
|
||||||
|
note: "unless 引导的是条件,不是原因:别用它回答 why 的问题。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "I took an umbrella ___ it was raining.", options: ["so", "because", "although"], answer: 1, explain: "后面是原因 → because。" },
|
||||||
|
{ q: "It was cold, ___ we wore coats.", options: ["because", "so", "unless"], answer: 1, explain: "后面是结果 → so。" },
|
||||||
|
{ q: "___ he is young, he can cook well.", options: ["Because", "Although", "Unless"], answer: 1, explain: "年纪小却会做饭,转折 → Although。" },
|
||||||
|
{ q: "You can’t play outside ___ you finish your homework.", options: ["although", "because", "unless"], answer: 2, explain: "“除非做完作业”→ unless。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "She was happy ___ she passed the test.", options: ["so", "because", "unless"], answer: 1, explain: "通过考试是原因 → because。" },
|
||||||
|
{ q: "He was tired, ___ he went to bed early.", options: ["so", "because", "although"], answer: 0, explain: "早睡是结果 → so。" },
|
||||||
|
{ q: "___ you practise, you won’t improve.", options: ["Although", "Because", "Unless"], answer: 2, explain: "“如果不练习”→ Unless。" },
|
||||||
|
{ q: "Which sentence is correct?", options: ["Because it rained, so we stayed in.", "Although it rained, but we went out.", "Although it rained, we went out."], answer: 2, explain: "although 与 but、because 与 so 不能并用。" },
|
||||||
|
{ q: "___ it was late, we went home.", options: ["Because", "Although", "Unless"], answer: 0, explain: "天晚了是回家的原因 → Because。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "lesson",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "Linking & sequencing words",
|
||||||
|
goal: "用连接词和顺序词把句子与段落连贯起来(补充、举例、转折、顺序)。",
|
||||||
|
sections: [
|
||||||
|
{
|
||||||
|
heading: "Why we use linking words",
|
||||||
|
zh: "连接词把整句、整段串起来,让思路清晰、文章流畅。",
|
||||||
|
body: "So far we linked ideas inside one sentence. Now we connect whole sentences and paragraphs. Linking words (also called connectives) guide the reader through your thinking: they add points, show results, give examples, or mark time. A short paragraph without them feels choppy and disconnected; with them, it flows smoothly. They usually start a new sentence and are followed by a comma.",
|
||||||
|
examples: ["He is clever. Moreover, he works very hard."],
|
||||||
|
note: "连接词放句首时,后面几乎总要跟一个逗号:However, … / For example, …",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Adding and giving examples",
|
||||||
|
zh: "补充用 also / in addition;举例用 for example / for instance。",
|
||||||
|
body: "To add another point, use “also”, “in addition”, “moreover”, or “furthermore”: “She sings well. In addition, she dances beautifully.” To introduce an example, use “for example” or “for instance”: “Many fruits are rich in vitamin C. For example, oranges and kiwis contain a lot.” “Also” often sits in the middle of a sentence rather than at the start: “He also plays the guitar.”",
|
||||||
|
examples: ["I speak English. I also speak a little French."],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Result and contrast",
|
||||||
|
zh: "however 表转折(另起一句);therefore / as a result 表结果。",
|
||||||
|
body: "Across sentences, “however” shows contrast, much like “although” but starting a new sentence: “The exam was hard. However, most students passed.” “Therefore” and “as a result” show a result: “He practised every day. As a result, he won the match.” These words are more formal than “but” and “so”, and they love a comma right after them.",
|
||||||
|
structure: {
|
||||||
|
cols: ["function", "words", "example"],
|
||||||
|
rows: [
|
||||||
|
["add", "also, in addition", "She also paints."],
|
||||||
|
["example", "for example, for instance", "For example, apples."],
|
||||||
|
["contrast", "however", "It rained. However, we went out."],
|
||||||
|
["sequence", "first, then, next, finally", "First, wash the rice."],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
examples: ["The road was closed. Therefore, we took a longer way."],
|
||||||
|
note: "but / so 连在句子里;however / therefore 通常另起一句,更正式。",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
heading: "Sequencing: ordering steps",
|
||||||
|
zh: "讲步骤或经过用 first → then → next → after that → finally。",
|
||||||
|
body: "When we explain a process or tell events in order, sequencing words number the steps. Use “first / first of all”, “then”, “next”, “after that”, and “finally”: “First, boil the water. Then, add the noodles. After that, cook them for five minutes. Finally, add the sauce.” They make instructions and stories easy to follow. “Finally” marks the last step of a plan; “at last” suggests a long, tiring wait.",
|
||||||
|
examples: ["First I woke up. Next I had breakfast. Finally I caught the bus."],
|
||||||
|
note: "“Finally” = 最后一步;“at last” = 终于(等了很久),两者语气不同。",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
practice: [
|
||||||
|
{ q: "He is smart. ___, he works hard.", options: ["However", "In addition", "For example"], answer: 1, explain: "补充另一个优点 → In addition。" },
|
||||||
|
{ q: "Many fruits are healthy. ___, apples and bananas.", options: ["For example", "However", "Finally"], answer: 0, explain: "后面是例子 → For example。" },
|
||||||
|
{ q: "___, mix the eggs and sugar.", options: ["Finally", "First", "However"], answer: 1, explain: "第一步 → First。" },
|
||||||
|
{ q: "It was expensive. ___, I bought it.", options: ["However", "For example", "First"], answer: 0, explain: "贵却还是买了,转折 → However。" },
|
||||||
|
],
|
||||||
|
quiz: [
|
||||||
|
{ q: "She speaks French. ___, she speaks German.", options: ["In addition", "For example", "First"], answer: 0, explain: "补充同类信息 → In addition。" },
|
||||||
|
{ q: "___, turn off the computer.", options: ["First", "Finally", "However"], answer: 1, explain: "最后一步 → Finally。" },
|
||||||
|
{ q: "He studied hard. ___, he got a high score.", options: ["However", "As a result", "For example"], answer: 1, explain: "高分是结果 → As a result。" },
|
||||||
|
{ q: "The film was long. ___, it was boring.", options: ["However", "Also", "Then"], answer: 0, explain: "补充一个相反的缺点,另起一句用 However 也可表递进式转折;此处语义为让步转折 → However。" },
|
||||||
|
{ q: "Which sequence order is natural?", options: ["Finally, First, Then", "First, Then, Finally", "Then, Finally, First"], answer: 1, explain: "自然顺序:First → Then → Finally。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "weekly",
|
||||||
|
cefr: "B1",
|
||||||
|
title: "第 9 周测验",
|
||||||
|
intro: "本周你学了推测性情态动词、反意疑问句、动名词与不定式、冠词、连词和连接顺序词。下面 10 题综合检测,≥80% 通过。",
|
||||||
|
quiz: [
|
||||||
|
{ q: "He’s been working all day. He ___ be tired.", options: ["must", "can’t", "mustn’t"], answer: 0, explain: "几乎肯定的推测 → must。" },
|
||||||
|
{ q: "She ___ be a child — she drives a car!", options: ["must", "can’t", "might"], answer: 1, explain: "几乎不可能 → can’t。" },
|
||||||
|
{ q: "You’re new here, ___ you?", options: ["are", "aren’t", "don’t"], answer: 1, explain: "前肯后否,重复 are:aren’t you。" },
|
||||||
|
{ q: "She likes reading, ___ she?", options: ["doesn’t", "isn’t", "does"], answer: 0, explain: "一般现在时借 does,前肯后否。" },
|
||||||
|
{ q: "I enjoy ___ to music.", options: ["to listen", "listening", "listen"], answer: 1, explain: "enjoy 后接 -ing。" },
|
||||||
|
{ q: "We decided ___ a picnic.", options: ["having", "to have", "have"], answer: 1, explain: "decide 后接 to + 动词。" },
|
||||||
|
{ q: "I love ___ . It’s free.", options: ["a music", "the music", "music"], answer: 2, explain: "不可数名词泛指 → 零冠词。" },
|
||||||
|
{ q: "___ you hurry, you’ll miss the bus.", options: ["Although", "Unless", "Because"], answer: 1, explain: "“如果不快点”→ Unless。" },
|
||||||
|
{ q: "He was ill. ___, he went to school.", options: ["However", "Because", "For example"], answer: 0, explain: "生病却去上学,转折另起一句 → However。" },
|
||||||
|
{ q: "She can sing. ___, she can dance.", options: ["In addition", "Unless", "Because"], answer: 0, explain: "补充同类才能 → In addition。" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -12,6 +12,9 @@ import {
|
|||||||
varchar,
|
varchar,
|
||||||
} from "drizzle-orm/mysql-core";
|
} from "drizzle-orm/mysql-core";
|
||||||
|
|
||||||
|
// 科目枚举(打卡分类)
|
||||||
|
export const SUBJECT_VALUES = ["chinese", "math", "english", "exercise", "other"] as const;
|
||||||
|
|
||||||
// ===== 家庭 =====
|
// ===== 家庭 =====
|
||||||
export const families = mysqlTable("family", {
|
export const families = mysqlTable("family", {
|
||||||
id: bigint("id", { mode: "number" }).primaryKey().autoincrement(),
|
id: bigint("id", { mode: "number" }).primaryKey().autoincrement(),
|
||||||
@@ -85,6 +88,7 @@ export const taskTemplates = mysqlTable(
|
|||||||
// 0=周日,1=周一……6=周六(与 JS Date.getDay 一致)
|
// 0=周日,1=周一……6=周六(与 JS Date.getDay 一致)
|
||||||
dow: int("dow").notNull(),
|
dow: int("dow").notNull(),
|
||||||
title: varchar("title", { length: 100 }).notNull(),
|
title: varchar("title", { length: 100 }).notNull(),
|
||||||
|
subject: mysqlEnum("subject", SUBJECT_VALUES).notNull().default("other"),
|
||||||
requiresPhoto: boolean("requires_photo").notNull().default(false),
|
requiresPhoto: boolean("requires_photo").notNull().default(false),
|
||||||
sortOrder: int("sort_order").notNull().default(0),
|
sortOrder: int("sort_order").notNull().default(0),
|
||||||
createdAt: datetime("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
createdAt: datetime("created_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
||||||
@@ -103,6 +107,7 @@ export const taskInstances = mysqlTable(
|
|||||||
// 任务日期,字符串 YYYY-MM-DD,避免时区漂移
|
// 任务日期,字符串 YYYY-MM-DD,避免时区漂移
|
||||||
date: date("date", { mode: "string" }).notNull(),
|
date: date("date", { mode: "string" }).notNull(),
|
||||||
title: varchar("title", { length: 100 }).notNull(),
|
title: varchar("title", { length: 100 }).notNull(),
|
||||||
|
subject: mysqlEnum("subject", SUBJECT_VALUES).notNull().default("other"),
|
||||||
requiresPhoto: boolean("requires_photo").notNull().default(false),
|
requiresPhoto: boolean("requires_photo").notNull().default(false),
|
||||||
status: mysqlEnum("status", ["pending", "done"]).notNull().default("pending"),
|
status: mysqlEnum("status", ["pending", "done"]).notNull().default("pending"),
|
||||||
// 家长补卡标记,永久保留
|
// 家长补卡标记,永久保留
|
||||||
@@ -129,3 +134,20 @@ export const photos = mysqlTable(
|
|||||||
},
|
},
|
||||||
(t) => [index("idx_photo_instance").on(t.taskInstanceId)],
|
(t) => [index("idx_photo_instance").on(t.taskInstanceId)],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ===== 英语语法学习进度(按课程序列解锁,测验达标才算通过)=====
|
||||||
|
export const grammarProgress = mysqlTable(
|
||||||
|
"grammar_progress",
|
||||||
|
{
|
||||||
|
id: bigint("id", { mode: "number" }).primaryKey().autoincrement(),
|
||||||
|
childUserId: bigint("child_user_id", { mode: "number" })
|
||||||
|
.notNull()
|
||||||
|
.references(() => users.id, { onDelete: "cascade" }),
|
||||||
|
// 课程序列号(1 起,含每日课、周测、月测,线性解锁)
|
||||||
|
seq: int("seq").notNull(),
|
||||||
|
score: int("score"), // 测验得分 0-100
|
||||||
|
passed: boolean("passed").notNull().default(false),
|
||||||
|
completedAt: datetime("completed_at").notNull().default(sql`CURRENT_TIMESTAMP`),
|
||||||
|
},
|
||||||
|
(t) => [uniqueIndex("uq_grammar_child_seq").on(t.childUserId, t.seq)],
|
||||||
|
);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import type { Cefr } from "@/content/grammar/types";
|
||||||
|
|
||||||
|
// CEFR 级别配色(徽章与进度用)
|
||||||
|
export const CEFR_STYLE: Record<Cefr, { label: string; cls: string }> = {
|
||||||
|
A1: { label: "A1 入门", cls: "bg-emerald-100 text-emerald-700" },
|
||||||
|
A2: { label: "A2 基础", cls: "bg-sky-100 text-sky-700" },
|
||||||
|
B1: { label: "B1 进阶", cls: "bg-indigo-100 text-indigo-700" },
|
||||||
|
B2: { label: "B2 中高", cls: "bg-violet-100 text-violet-700" },
|
||||||
|
C1: { label: "C1 高级", cls: "bg-amber-100 text-amber-700" },
|
||||||
|
};
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { and, eq, sql } from "drizzle-orm";
|
||||||
|
import { db } from "@/db";
|
||||||
|
import { grammarProgress, taskInstances } from "@/db/schema";
|
||||||
|
import { todayStr } from "@/lib/dates";
|
||||||
|
import { SYLLABUS, TOTAL, entryBySeq } from "@/content/grammar";
|
||||||
|
|
||||||
|
// 已通过的课程序列集合
|
||||||
|
export async function passedSet(childId: number): Promise<Set<number>> {
|
||||||
|
const rows = await db
|
||||||
|
.select({ seq: grammarProgress.seq })
|
||||||
|
.from(grammarProgress)
|
||||||
|
.where(and(eq(grammarProgress.childUserId, childId), eq(grammarProgress.passed, true)));
|
||||||
|
return new Set(rows.map((r) => r.seq));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下一个该学的序列(第一个未通过的);全部完成返回 TOTAL+1
|
||||||
|
export async function nextSeq(childId: number): Promise<number> {
|
||||||
|
const passed = await passedSet(childId);
|
||||||
|
for (const e of SYLLABUS) if (!passed.has(e.seq)) return e.seq;
|
||||||
|
return TOTAL + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解锁规则:第 1 课永远开放;其余需前一课已通过
|
||||||
|
export function isUnlocked(seq: number, passed: Set<number>): boolean {
|
||||||
|
return seq === 1 || passed.has(seq - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录某课结果;通过则同步完成当天的英语打卡
|
||||||
|
export async function completeSeq(
|
||||||
|
childId: number,
|
||||||
|
seq: number,
|
||||||
|
score: number,
|
||||||
|
passed: boolean,
|
||||||
|
) {
|
||||||
|
await db
|
||||||
|
.insert(grammarProgress)
|
||||||
|
.values({ childUserId: childId, seq, score, passed })
|
||||||
|
.onDuplicateKeyUpdate({ set: { score, passed, completedAt: sql`CURRENT_TIMESTAMP` } });
|
||||||
|
|
||||||
|
if (!passed) return;
|
||||||
|
|
||||||
|
const entry = entryBySeq(seq);
|
||||||
|
if (!entry) return;
|
||||||
|
const title = entry.type === "lesson" ? `英语语法 · ${entry.title}` : entry.title;
|
||||||
|
const today = todayStr();
|
||||||
|
|
||||||
|
const [existing] = await db
|
||||||
|
.select({ id: taskInstances.id, status: taskInstances.status })
|
||||||
|
.from(taskInstances)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(taskInstances.childUserId, childId),
|
||||||
|
eq(taskInstances.date, today),
|
||||||
|
eq(taskInstances.title, title),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
if (existing.status !== "done") {
|
||||||
|
await db
|
||||||
|
.update(taskInstances)
|
||||||
|
.set({ status: "done", doneAt: sql`CURRENT_TIMESTAMP` })
|
||||||
|
.where(eq(taskInstances.id, existing.id));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await db.insert(taskInstances).values({
|
||||||
|
childUserId: childId,
|
||||||
|
date: today,
|
||||||
|
title,
|
||||||
|
subject: "english",
|
||||||
|
status: "done",
|
||||||
|
doneAt: new Date(),
|
||||||
|
sortOrder: 99,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 服务端计分:对比提交的答案,返回得分与每题对错,防作弊
|
||||||
|
export function grade(entryQuiz: { answer: number }[], answers: number[]) {
|
||||||
|
let correct = 0;
|
||||||
|
const detail = entryQuiz.map((q, i) => {
|
||||||
|
const right = answers[i] === q.answer;
|
||||||
|
if (right) correct++;
|
||||||
|
return right;
|
||||||
|
});
|
||||||
|
const score = entryQuiz.length ? Math.round((correct / entryQuiz.length) * 100) : 0;
|
||||||
|
return { score, passed: score >= 80, correct, total: entryQuiz.length, detail };
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// 极简加粗渲染:把 **文字** 转成 <strong>,其余按段落输出
|
||||||
|
export function renderBold(text: string): (string | { b: string })[] {
|
||||||
|
return text.split(/(\*\*[^*]+\*\*)/g).map((part) =>
|
||||||
|
part.startsWith("**") && part.endsWith("**") ? { b: part.slice(2, -2) } : part,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// 打卡科目元数据:标签 + 配色(色点/文字/浅底),供孩子端分组与家长端徽章共用
|
||||||
|
|
||||||
|
export const SUBJECTS = [
|
||||||
|
{ key: "chinese", label: "语文", dot: "bg-rose-500", text: "text-rose-600", soft: "bg-rose-50", ring: "ring-rose-200" },
|
||||||
|
{ key: "math", label: "数学", dot: "bg-sky-500", text: "text-sky-600", soft: "bg-sky-50", ring: "ring-sky-200" },
|
||||||
|
{ key: "english", label: "英语", dot: "bg-indigo-500", text: "text-indigo-600", soft: "bg-indigo-50", ring: "ring-indigo-200" },
|
||||||
|
{ key: "exercise", label: "运动", dot: "bg-emerald-500", text: "text-emerald-600", soft: "bg-emerald-50", ring: "ring-emerald-200" },
|
||||||
|
{ key: "other", label: "其他", dot: "bg-slate-400", text: "text-slate-500", soft: "bg-slate-100", ring: "ring-slate-200" },
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type Subject = (typeof SUBJECTS)[number]["key"];
|
||||||
|
|
||||||
|
export const SUBJECT_ORDER = SUBJECTS.map((s) => s.key);
|
||||||
|
|
||||||
|
// 未知值一律回落"其他",避免崩溃
|
||||||
|
export function subjectMeta(key: string) {
|
||||||
|
return SUBJECTS.find((s) => s.key === key) ?? SUBJECTS[SUBJECTS.length - 1];
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import { viewUrl } from "@/lib/oss";
|
|||||||
export type TaskView = {
|
export type TaskView = {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
subject: string;
|
||||||
requiresPhoto: boolean;
|
requiresPhoto: boolean;
|
||||||
status: "pending" | "done";
|
status: "pending" | "done";
|
||||||
isMakeup: boolean;
|
isMakeup: boolean;
|
||||||
@@ -36,6 +37,7 @@ export async function ensureDay(childId: number, date: string) {
|
|||||||
childUserId: childId,
|
childUserId: childId,
|
||||||
date,
|
date,
|
||||||
title: t.title,
|
title: t.title,
|
||||||
|
subject: t.subject,
|
||||||
requiresPhoto: t.requiresPhoto,
|
requiresPhoto: t.requiresPhoto,
|
||||||
sortOrder: t.sortOrder,
|
sortOrder: t.sortOrder,
|
||||||
sourceTemplateId: t.id,
|
sourceTemplateId: t.id,
|
||||||
@@ -52,6 +54,7 @@ export async function dayTasks(childId: number, date: string): Promise<TaskView[
|
|||||||
.select({
|
.select({
|
||||||
id: taskInstances.id,
|
id: taskInstances.id,
|
||||||
title: taskInstances.title,
|
title: taskInstances.title,
|
||||||
|
subject: taskInstances.subject,
|
||||||
requiresPhoto: taskInstances.requiresPhoto,
|
requiresPhoto: taskInstances.requiresPhoto,
|
||||||
status: taskInstances.status,
|
status: taskInstances.status,
|
||||||
isMakeup: taskInstances.isMakeup,
|
isMakeup: taskInstances.isMakeup,
|
||||||
|
|||||||
Reference in New Issue
Block a user