Compare commits

..

No commits in common. "main" and "master" have entirely different histories.
main ... master

1889 changed files with 1 additions and 246330 deletions

3
.idea/.gitignore vendored
View File

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings" defaultProject="true" />
</project>

202
LICENSE
View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to the Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by the Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. Please also get an ISBN
number for the printed version if you plan to publish a book
using this license. We recommend considering the
Apache License 2.0 for software, and the CC-BY license for
other creative works.
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,2 +1,2 @@
计算思维程序实践共14个计算思维程序实践项目编写开源鸿蒙应用程序为学生系统剖析了每一个实践项目的计算思维为学生搭建了一个五级阶梯的程序实现路径同时为学生提供了由零基础开发到最终系统实现的初始版程序和程序实现环境供学生上机调试与研讨。 # TSZQ_KaiYuanHongMengRISC-VJuShenZhiNengKeChengGongJianZhuanQu

21
THANKS
View File

@ -1,21 +0,0 @@
This project thanks the following people for their contributions
(bug reports, testing, suggestions, documentation, or other non-code help):
- Li Ju
- An Xiaoxin
- Yang Yang
- Luo Wanxu
- Ji Ruijin
- Qiu Jiayu
- Zhang Yukai
- Lai Zijie
- Zhuang Yaojian
- Yao Yubin
- Chen Yunfeng
- Yao Xintao
- Chen Yanbo
- Xie Canquan
- Liu Guihong
- Fu Haiyao
- Yang Zhenwei
- Han Xinyu

View File

@ -1,21 +0,0 @@
# databasing
### 1、项目说明
总体思路关系数据库系统项目开发的总体思路如图1.1示意可交互式练习SQL语句构造与执行的系统1建立一个示例数据库SCT 内中包含3个数据表Student, SC和Course注意本书是以SCT为例读者做实验时可选择建立其他的数据库和数据表2利用Insert语句对示例数据库的各个表追加内容3利用Select语句检索示例数据库并显示检索结果4编制应用程序使用户可以针对固定的表输入检索条件系统自动构造SQL语句并执行该SQL语句完成检索并输出检索结果。5编制应用程序使用户可以对数据库中的任何表进行检索条件输入并构造SQL语句、执行SQL语句显示检索结果。
图1.1 项目开发的总体思路图
<img src="figs/overall.png" width=80% /></center>
### 2、开发环境说明
1系统版本OpenHarmony 4.0 Release
2SDK版本API 10
3Model类型Stage
4DevEco Studio版本Deveco Studio 4.0 release
5硬件环境Unionpi Whale、RK3566开发板
6预览器参数(1)DeviceType:default;(2)Resolution:560-1280;(3)DPI:240;其余参数自定。
### 3、项目主要函数调用关系图与项目输出界面演进图
图3.1 项目主要函数调用关系图
<img src="figs/relation.png" width=80% /></center>
图3.2 项目输出界面演进图
<img src="figs/evolution.png" width=80% /></center>

View File

@ -1,11 +0,0 @@
/node_modules
/oh_modules
/local.properties
/.idea
**/build
/.hvigor
.cxx
/.clangd
/.clang-format
/.clang-tidy
**/.test

View File

@ -1,11 +0,0 @@
{
"app": {
"bundleName": "com.example.database13",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}

View File

@ -1,8 +0,0 @@
{
"string": [
{
"name": "app_name",
"value": "database13"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,49 +0,0 @@
{
"app": {
"signingConfigs": [
{
"name": "default",
"material": {
"certpath": "C:\\Users\\HP\\.ohos\\config\\openharmony\\auto_ohos_default_database15_com.example.database13.cer",
"storePassword": "0000001BA3E2965E301A7181B96C92E73BB162C179834F285268D3B71F5F4F585B7AE35294E33B45C5523C",
"keyAlias": "debugKey",
"keyPassword": "0000001B45786F06248E3CAF0728952F4C3C3B287B3A46C1D0816136C37458692661BC4149C8FA815A989E",
"profile": "C:\\Users\\HP\\.ohos\\config\\openharmony\\auto_ohos_default_database15_com.example.database13.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "C:\\Users\\HP\\.ohos\\config\\openharmony\\auto_ohos_default_database15_com.example.database13.p12"
}
}
],
"products": [
{
"name": "default",
"signingConfig": "default",
"compileSdkVersion": 10,
"compatibleSdkVersion": 9,
"runtimeOS": "OpenHarmony"
}
],
"buildModeSet": [
{
"name": "debug",
},
{
"name": "release"
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}

View File

@ -1,6 +0,0 @@
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test

View File

@ -1,30 +0,0 @@
{
"apiType": "stageMode",
"buildOption": {
"arkOptions": {
// "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation" : {
"ruleOptions":{
"enable": true,
"files": ["./obfuscation-rules.txt"]
}
}
}
},
],
"targets": [
{
"name": "default"
}
,
{
"name": "ohosTest",
}
]
}

View File

@ -1,6 +0,0 @@
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}

View File

@ -1,18 +0,0 @@
# Define project specific obfuscation rules here.
# You can include the obfuscation configuration files in the current module's build-profile.json5.
#
# For more details, see
# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
# Obfuscation options:
# -disable-obfuscation: disable all obfuscations
# -enable-property-obfuscation: obfuscate the property names
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
# -compact: remove unnecessary blank spaces and all line feeds
# -remove-log: remove all console.* statements
# -print-namecache: print the name cache that contains the mapping from the old names to new names
# -apply-namecache: reuse the given cache file
# Keep options:
# -keep-property-name: specifies property names that you want to keep
# -keep-global-name: specifies names that you want to keep in the global scope

View File

@ -1,10 +0,0 @@
{
"license": "",
"devDependencies": {},
"author": "",
"name": "entry",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -1,562 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import relationalStore from '@ohos.data.relationalStore';
import Student from './student'
import Course from './course'
import Sc from './sc'
import ThreeTable from './ThreeTable'
export default class RdbUtils {
private static rdbStore: relationalStore.RdbStore;
// 初始化
static setStore(store: relationalStore.RdbStore) {
RdbUtils.rdbStore = store;
}
static getStore(): relationalStore.RdbStore {
return RdbUtils.rdbStore;
}
// 创建表
static executeSql(sql: string): Promise<void> {
return RdbUtils.getStore().executeSql(sql);
}
// 插入数据
static insert(tableName: string, data: any): Promise<number> {
return RdbUtils.getStore().insert(tableName, data);
}
// 查询并且加载学生表所有信息
static queryAllStudent(): Promise<Array<Student>> {
let predicates = new relationalStore.RdbPredicates('Student');
return new Promise<Array<Student>>((resolve, reject) => {
RdbUtils.getStore().query(predicates).then((result) => {
let students = new Array<Student>();
while (result.goToNextRow()) {
let student = new Student();
student.sid = result.getLong(result.getColumnIndex("sid"));
student.sname = result.getString(result.getColumnIndex('sname'));
student.ssex = result.getString(result.getColumnIndex("ssex"));
student.sage = result.getLong(result.getColumnIndex("sage"));
student.sclass = result.getLong(result.getColumnIndex("sclass"));
students.push(student);
}
resolve(students);
}).catch((error) => {
reject(error)
})
})
}
// 具体查询学生表信息
static queryStudent(columns:string[], full_sql_text:string): Promise<Array<Student>> {
return new Promise<Array<Student>>((resolve, reject) => {
RdbUtils.getStore().querySql(full_sql_text).then((result) => {
let students = new Array<Student>();
while (result.goToNextRow()) {
let student = new Student();
if (columns[0].includes('*')) {
student.sid = result.getLong(result.getColumnIndex("sid"));
student.sname = result.getString(result.getColumnIndex('sname'));
student.ssex = result.getString(result.getColumnIndex("ssex"));
student.sage = result.getLong(result.getColumnIndex("sage"));
student.sclass = result.getLong(result.getColumnIndex("sclass"));
}
else {
for (let i = 0; i < columns.length; i++) {
if (columns[i].includes('sid')) {
student.sid = result.getLong(result.getColumnIndex("sid"));
}
else if (columns[i].includes('sname')) {
student.sname = result.getString(result.getColumnIndex('sname'));
}
else if (columns[i].includes('ssex')) {
student.ssex = result.getString(result.getColumnIndex("ssex"));
}
else if (columns[i].includes('sage')) {
student.sage = result.getLong(result.getColumnIndex("sage"));
}
else if (columns[i].includes('sclass')) {
student.sclass = result.getLong(result.getColumnIndex("sclass"));
}
}
}
students.push(student);
}
resolve(students);
}).catch((error) => {
reject(error)
})
})
}
// 查询并且加载课程表所有信息
static queryAllCourse(): Promise<Array<Course>> {
let predicates = new relationalStore.RdbPredicates('Course');
return new Promise<Array<Course>>((resolve, reject) => {
RdbUtils.getStore().query(predicates).then((result) => {
let courses = new Array<Course>();
while (result.goToNextRow()) {
let course = new Course();
course.cid = result.getLong(result.getColumnIndex("cid"));
course.cname = result.getString(result.getColumnIndex('cname'));
course.credit = result.getDouble(result.getColumnIndex("credit"));
course.chours = result.getLong(result.getColumnIndex("chours"));
courses.push(course);
}
resolve(courses);
}).catch((error) => {
reject(error)
})
})
}
// 具体查询课程表信息
static queryCourse(columns:string[],full_sql_text:string): Promise<Array<Course>> {
let predicates = new relationalStore.RdbPredicates('Course')
return new Promise<Array<Course>>((resolve, reject) => {
RdbUtils.getStore().querySql(full_sql_text).then((result) => {
let courses = new Array<Course>();
while (result.goToNextRow()) {
let course = new Course()
if (columns[0].includes('*')) {
course.cid = result.getLong(result.getColumnIndex("cid"));
course.cname = result.getString(result.getColumnIndex('cname'));
course.credit = result.getDouble(result.getColumnIndex("credit"));
course.chours = result.getLong(result.getColumnIndex("chours"));
}
else {
for (let i = 0; i < columns.length; i++) {
if (columns[i].includes('cid')) {
course.cid = result.getLong(result.getColumnIndex("cid"));
}
else if (columns[i].includes('cname')) {
course.cname = result.getString(result.getColumnIndex('cname'));
}
else if (columns[i].includes('credit')) {
course.credit = result.getDouble(result.getColumnIndex("credit"));
}
else if (columns[i].includes('chour')) {
course.chours = result.getLong(result.getColumnIndex("chours"));
}
}
}
courses.push(course);
}
resolve(courses);
}).catch((error) => {
console.error(`Query failed, code is ${error.code},message is ${error.message}`);
reject(error)
})
})
}
// 查询并且加载选课表所有信息
static queryAllSc(): Promise<Array<Sc>> {
let predicates = new relationalStore.RdbPredicates('Sc');
return new Promise<Array<Sc>>((resolve, reject) => {
RdbUtils.getStore().query(predicates).then((result) => {
let scs = new Array<Sc>();
while (result.goToNextRow()) {
let sc = new Sc();
sc.sid = result.getLong(result.getColumnIndex("sid"));
sc.cid = result.getLong(result.getColumnIndex("cid"));
sc.score = result.getLong(result.getColumnIndex('score'));
scs.push(sc);
}
resolve(scs);
}).catch((error) => {
reject(error)
})
})
}
// 具体查询选课表所有信息
static querySc(columns:string[],full_sql_text:string): Promise<Array<Sc>> {
let predicates = new relationalStore.RdbPredicates('Sc');
return new Promise<Array<Sc>>((resolve, reject) => {
RdbUtils.getStore().querySql(full_sql_text).then((result) => {
let scs = new Array<Sc>();
while (result.goToNextRow()) {
let sc = new Sc();
if (columns[0].includes('*')) {
sc.sid = result.getLong(result.getColumnIndex("sid"));
sc.cid = result.getLong(result.getColumnIndex("cid"));
sc.score = result.getLong(result.getColumnIndex('score'));
}
else {
for (let i = 0; i < columns.length; i++) {
if (columns[i].includes('sid')) {
sc.sid = result.getLong(result.getColumnIndex("sid"));
}
if (columns[i].includes('cid')) {
sc.cid = result.getLong(result.getColumnIndex("cid"));
}
else if (columns[i].includes('score')) {
sc.score = result.getLong(result.getColumnIndex('score'));
}
}
}
scs.push(sc);
}
resolve(scs);
}).catch((error) => {
reject(error)
})
})
}
// 多表查询
static queryThreeTable(columns:string[], full_sql_text:string): Promise<Array<ThreeTable>> {
return new Promise<Array<ThreeTable>>((resolve, reject) => {
RdbUtils.getStore().querySql(full_sql_text).then((result) => {
let threetables = new Array<ThreeTable>();
while (result.goToNextRow()) {
let threetable = new ThreeTable();
if (columns[0].includes('*')) {
threetable.sid = result.getLong(result.getColumnIndex("s.sid"));
threetable.sname = result.getString(result.getColumnIndex('s.sname'));
threetable.ssex = result.getString(result.getColumnIndex("s.ssex"));
threetable.sage = result.getLong(result.getColumnIndex("s.sage"));
threetable.sclass = result.getLong(result.getColumnIndex("s.sclass"));
threetable.score = result.getLong(result.getColumnIndex("sc.score"));
threetable.cid = result.getLong(result.getColumnIndex("c.cid"));
threetable.cname = result.getString(result.getColumnIndex("c.cname"));
threetable.credit = result.getLong(result.getColumnIndex("c.credit"));
threetable.chours = result.getLong(result.getColumnIndex("c.chours"));
}
else {
for (let i = 0; i < columns.length; i++) {
if (columns[i].includes('sid')) {
threetable.sid = result.getLong(result.getColumnIndex("s.sid"));
}
else if (columns[i].includes('sname')) {
threetable.sname = result.getString(result.getColumnIndex('s.sname'));
}
else if (columns[i].includes('ssex')) {
threetable.ssex = result.getString(result.getColumnIndex("s.ssex"));
}
else if (columns[i].includes('sage')) {
threetable.sage = result.getLong(result.getColumnIndex("s.sage"));
}
else if (columns[i].includes('sclass')) {
threetable.sclass = result.getLong(result.getColumnIndex("s.sclass"));
}
else if (columns[i].includes('score')) {
threetable.score = result.getLong(result.getColumnIndex("sc.score"));
}
else if (columns[i].includes('cid')) {
threetable.cid = result.getLong(result.getColumnIndex("c.cid"));
}
else if (columns[i].includes('cname')) {
threetable.cname = result.getString(result.getColumnIndex("c.cname"));
}
else if (columns[i].includes('credit')) {
threetable.credit = result.getLong(result.getColumnIndex("c.credit"));
}
else if (columns[i].includes('chours')) {
threetable.chours = result.getLong(result.getColumnIndex("c.chours"));
}
}
}
threetables.push(threetable);
}
resolve(threetables);
}).catch((error) => {
reject(error)
})
})
}
}
export class SQLGenerator {
input_sid: string;
input_sname: string;
input_sclass: string;
input_ssex: string;
input_start_age: string;
input_end_age: string;
input_sage: string;
input_cid: string;
input_cname: string;
input_credit: string;
input_chours: string;
input_score: string;
sid_var: boolean;
sname_var: boolean;
ssex_var: boolean;
sage_var: boolean;
sclass_var: boolean;
cid_var: boolean;
cname_var: boolean;
credit_var: boolean;
chours_var: boolean;
score_var: boolean;
sql_text: string;
full_sql_text: string;
columns: string[];
input_low_score: string;
input_high_score: string;
constructor() {
this.input_sid = '';
this.input_sname = '';
this.input_sclass = '';
this.input_ssex = '';
this.input_start_age = '';
this.input_end_age = '';
this.input_sage = '';
this.input_start_age = '';
this.input_end_age = '';
this.input_cid = '';
this.input_cname = '';
this.input_credit = '';
this.input_chours = '';
this.input_score = '';
this.input_low_score = '';
this.input_high_score = '';
this.sid_var = false;
this.sname_var = false;
this.ssex_var = false;
this.sage_var = false;
this.sclass_var = false;
this.cid_var = false;
this.cname_var = false;
this.credit_var = false;
this.chours_var = false;
this.score_var = false;
this.sql_text = "";
this.full_sql_text = "";
this.columns = ["*"];
}
makeStudentSQL(): void {
this.sql_text = "select * from student where 1=1"
if (this.input_sid !== "") {
this.sql_text = this.sql_text + ' and (sid like ' + `'${this.input_sid}'` + ')';
}
if (this.input_sname !== "") {
this.sql_text = this.sql_text + ' and (sname like ' + `'${this.input_sname}'` + ')';
}
if (this.input_ssex !== "") {
this.sql_text = this.sql_text + ' and (ssex like ' + `'${this.input_ssex}'` + ')';
}
if (this.input_sage !== "") {
this.sql_text = this.sql_text + ' and (sage like ' + `'${this.input_sage}'` + ')';
}
if (this.input_sclass !== "") {
this.sql_text = this.sql_text + ' and (sclass like ' + `'${this.input_sclass}'` + ')';
}
if (this.input_start_age !== "") {
this.sql_text = this.sql_text + ' and (sage > ' + `'${this.input_start_age}'` + ')';
}
if (this.input_end_age !== "") {
this.sql_text = this.sql_text + ' and (sage < ' + `'${this.input_end_age}'` + ')';
}
if (this.sql_text == 'select * from student where 1=1') {
this.sql_text = "select * from student"
} else {
this.sql_text = this.sql_text.replace("1=1 and", "")
}
console.log('this.sql_text='+this.sql_text);
if (!this.sid_var && !this.sname_var && !this.ssex_var && !this.sage_var && !this.sclass_var) {
this.columns = ["*"];
} else {
this.columns = [];
if (this.sid_var) {
this.columns.push("sid");
}
if (this.sname_var) {
this.columns.push("sname");
}
if (this.ssex_var) {
this.columns.push("ssex");
}
if (this.sage_var) {
this.columns.push("sage");
}
if (this.sclass_var) {
this.columns.push("sclass");
}
}
let sqlQuery = `${this.columns.join(', ')}`;
this.sql_text = this.sql_text.replace('*',sqlQuery)
}
makeCourseSQL(): void {
this.sql_text = "select * from course where 1=1"
if (this.input_cid !== "") {
this.sql_text = this.sql_text + ' and (cid like ' + `'${this.input_cid}'` + ')';
}
if (this.input_cname !== "") {
this.sql_text = this.sql_text + ' and (cname like ' + `'${this.input_cname}'` + ')';
}
if (this.input_credit !== "") {
this.sql_text = this.sql_text + ' and (credit like ' + `'${this.input_credit}'` + ')';
}
if (this.input_chours !== "") {
this.sql_text = this.sql_text + ' and (chours like ' + `'${this.input_chours}'` + ')';
}
if (this.sql_text == 'select * from course where 1=1') {
this.sql_text = "select * from course"
} else {
this.sql_text = this.sql_text.replace("1=1 and", "")
}
console.log('this.sql_text='+this.sql_text);
if (!this.cid_var && !this.cname_var && !this.credit_var && !this.chours_var) {
this.columns = ["*"];
} else {
this.columns = [];
if (this.cid_var) {
this.columns.push("cid");
}
if (this.cname_var) {
this.columns.push("cname");
}
if (this.credit_var) {
this.columns.push("credit");
}
if (this.chours_var) {
this.columns.push("chours");
}
}
let sqlQuery = `${this.columns.join(', ')}`;
this.sql_text = this.sql_text.replace('*',sqlQuery)
}
makeScSQL(): void {
this.sql_text = "select * from sc where 1=1"
if (this.input_sid !== "") {
this.sql_text = this.sql_text + ' and (sid like ' + `'${this.input_sid}'` + ')';
}
if (this.input_cid !== "") {
this.sql_text = this.sql_text + ' and (cid like ' + `'${this.input_cid}'` + ')';
}
if (this.input_score !== "") {
this.sql_text = this.sql_text + ' and (score like ' + `'${this.input_score}'` + ')';
}
if (this.sql_text == 'select * from sc where 1=1') {
this.sql_text = "select * from sc"
} else {
this.sql_text = this.sql_text.replace("1=1 and", "")
}
console.log('this.sql_text='+this.sql_text);
if (!this.sid_var && !this.cid_var && !this.score_var) {
this.columns = ["*"];
} else {
this.columns = [];
if (this.sid_var) {
this.columns.push("sid");
}
if (this.cid_var) {
this.columns.push("cid");
}
if (this.score_var) {
this.columns.push("score");
}
}
let sqlQuery = `${this.columns.join(', ')}`;
this.sql_text = this.sql_text.replace('*',sqlQuery)
}
makeThreeeTableSQL(): void {
this.sql_text = "select * from student s join sc on sc.sid=s.sid join course c on c.cid=sc.cid where 1=1"
if (this.input_sid !== "") {
this.sql_text = this.sql_text + ' and (s.sid like ' + `'${this.input_sid}'` + ')';
}
if (this.input_sname !== "") {
this.sql_text = this.sql_text + ' and (s.sname like ' + `'${this.input_sname}'` + ')';
}
if (this.input_sclass !== "") {
this.sql_text = this.sql_text + ' and (s.sclass like ' + `'${this.input_sclass}'` + ')';
}
if (this.input_ssex !== "") {
this.sql_text = this.sql_text + ' and (s.ssex like ' + `'${this.input_ssex}'` + ')';
}
if (this.input_start_age !== "") {
this.sql_text = this.sql_text + ' and (s.sage > ' + `'${this.input_start_age}'` + ')';
}
if (this.input_end_age !== "") {
this.sql_text = this.sql_text + ' and (s.sage < ' + `'${this.input_end_age}'` + ')';
}
if (this.input_cid !== "") {
this.sql_text = this.sql_text + ' and (c.cid like ' + `'${this.input_cid}'` + ')';
}
if (this.input_cname !== "") {
this.sql_text = this.sql_text + ' and (c.cname like ' + `'${this.input_cname}'` + ')';
}
if (this.input_low_score !== "") {
this.sql_text = this.sql_text + ' and (sc.score > ' + `'${this.input_score}'` + ')';
}
if (this.input_high_score !== "") {
this.sql_text = this.sql_text + ' and (sc.score < ' + `'${this.input_score}'` + ')';
}
if (this.sql_text == "select * from student s join sc on sc.sid=s.sid join course c on c.cid=sc.cid where 1=1"
) {
this.sql_text = "select * from student s join sc on sc.sid=s.sid join course c on c.cid=sc.cid"
} else {
this.sql_text = this.sql_text.replace("1=1 and", "")
}
console.log('this.sql_text='+this.sql_text);
if (!this.sid_var && !this.sname_var && !this.ssex_var && !this.sage_var && !this.sclass_var && !this.score_var && !this.cid_var && !this.cname_var) {
this.columns = ["*"];
} else {
this.columns = [];
if (this.sid_var) {
this.columns.push("s.sid");
}
if (this.sname_var) {
this.columns.push("s.sname");
}
if (this.ssex_var) {
this.columns.push("s.ssex");
}
if (this.sage_var) {
this.columns.push("s.sage");
}
if (this.sclass_var) {
this.columns.push("s.sclass");
}
if (this.score_var) {
this.columns.push("sc.score");
}
if (this.cid_var) {
this.columns.push("c.cid");
}
if (this.cname_var) {
this.columns.push("c.cname");
}
}
let sqlQuery = `${this.columns.join(', ')}`;
this.sql_text = this.sql_text.replace('*',sqlQuery)
}
}

View File

@ -1,40 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export default class ThreeTable {
sid: number; // 学生ID
sname: string; // 姓名
ssex: string; // 性别
sage: number | null; // 年龄允许为null
sclass: number | null; // 班级允许为null
score: number | null; // 成绩
cid: number; // 课程ID
cname: string; // 课程名字
credit: number | null; // 课程学分
chours: number | null; // 课程时长
constructor() {
this.sid = 0;
this.sname = '';
this.ssex = '';
this.sage = 0;
this.sclass = 0;
this.score = 0;
this.cid = 0;
this.cname = '';
this.credit = 0;
this.chours = 0;
}
}

View File

@ -1,28 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export default class Course {
cid: number; // 课程ID
cname: string; // 课程名字
chours: number | null; // 课程时长
credit: number | null; // 课程学分
constructor() {
this.cid = 0;
this.cname = '';
this.chours = 0;
this.credit = 0;
}
}

View File

@ -1,26 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export default class Sc {
sid: number | null; // 学生ID
cid: number | null; // 课程ID
score: number | null; // 成绩
constructor() {
this.sid = 0;
this.cid = 0;
this.score = 0;
}
}

View File

@ -1,30 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export default class Student {
sid: number; // 学生ID
sname: string; // 姓名
ssex: string; // 性别
sage: number | null; // 年龄允许为null
sclass: number | null; // 班级允许为null
constructor() {
this.sid = 0;
this.sname = '';
this.ssex = '';
this.sage = 0;
this.sclass = 0;
}
}

View File

@ -1,521 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import relationalStore from '@ohos.data.relationalStore'; // 导入模块
import Student from '../common/rdbUtils/student'
import RdbUtils from '../common/rdbUtils/RdbUtils';
import Sc from '../common/rdbUtils/sc'
import Course from '../common/rdbUtils/course';
import { SQLGenerator } from '../common/rdbUtils/RdbUtils'
@Component
export struct left {
@State flagCou:boolean =false
@State flagStu:boolean =false
@Link list1:Array<Student>;
@Link list2:Array<Course>;
@Link list3:Array<Sc>;
@Builder
itemHeadStu(t0: string, t1: string, t2:string ,t3:string,t4:string) {
Row() {
Text(t0)
.fontSize(15)
.padding(1)
.width(50)
.fontColor('#838eb0')
Text(t1)
.fontSize(15)
.padding(1)
.width(100)
.fontColor('#838eb0')
Text(t2)
.fontSize(15)
.padding(1)
.width(50)
.fontColor('#838eb0')
Text(t3)
.fontSize(15)
.width(50)
.fontColor('#838eb0')
.padding(1)
Text(t4)
.fontSize(15)
.width(50)
.fontColor('#838eb0')
.padding(1)
}
.backgroundColor(Color.White)
}
@Builder
itemHeadCou(t0: string, t1: string, t2:string ,t3:string) {
Row() {
Text(t0)
.fontSize(15)
.padding(1)
.fontColor('#838eb0')
.width(50)
Text(t1)
.fontSize(15)
.padding(1)
.fontColor('#838eb0')
.width(70)
Text(t2)
.fontSize(15)
.padding(1)
.fontColor('#838eb0')
.width(70)
Text(t3)
.fontSize(15)
.padding(1)
.fontColor('#838eb0')
.width(50)
}
.backgroundColor(Color.White)
}
@Builder
itemHeadSc(t0: string, t1: string, t2:string ) {
Row() {
Text(t0)
.fontSize(15)
.fontColor('#838eb0')
.padding(1)
Text(t1)
.fontSize(15)
.fontColor('#838eb0')
.padding(1)
Text(t2)
.fontSize(15)
.fontColor('#838eb0')
.padding(1)
}
.backgroundColor(Color.White)
.width('100%')
.justifyContent(FlexAlign.SpaceAround)
}
build() {
Column({space:5}) {
// student表
Column() {
// 表头行
Row({ space: 10 }) {
// 表头
Column() {
Text(' student ')
.fontSize(20)
.backgroundColor('#f0f5fa')
.fontColor('#838eb0')
.borderColor('#b9c7da')
}
Column() {
Text('装载')
.fontColor(Color.White)
.fontSize(12)
.padding(4)
.backgroundColor('#378dfc')
.onClick(() => {
this.flagStu=true
RdbUtils.queryAllStudent()
.then((students: Array<Student>) => {
this.list1 = students
}).catch((error) => {
openDialog('error' + error.toString())
})
})
}
}
.padding(5)
// 表单内容行
if (this.flagStu == true) {
Scroll() {
Column() {
List({ space: 5, initialIndex: 0 }) {
ListItemGroup({ header: this.itemHeadStu(' sid', ' sname', 'ssex', 'sage', 'sclass') }) {
ForEach(this.list1, (item: Student, index) => {
ListItem() {
Row() {
Column() {
Text(item.sid.toString())
.fontSize(10)
.padding(5)
.width(70)
}
.justifyContent(FlexAlign.SpaceAround)
Column() {
Text(item.sname)
.fontSize(10)
.padding(5)
.width(70)
}
.justifyContent(FlexAlign.SpaceAround)
Column() {
Text(item.ssex)
.fontSize(10)
.padding(5)
.width(70)
}
.justifyContent(FlexAlign.Center)
Column() {
Text(item.sage.toString())
.fontSize(10)
.padding(5)
.width(40)
}
.justifyContent(FlexAlign.SpaceAround)
Column() {
Text(item.sclass.toString())
.fontSize(10)
.padding(5)
.width(50)
}
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
}
})
}
}
.sticky(StickyStyle.Header)
.height('50%')
.listDirection(Axis.Vertical)
.scrollBar(BarState.Auto)
.backgroundColor('#f0f5fa')
}
.margin({ top: 5 ,bottom:5})
}.scrollable(ScrollDirection.Horizontal)
}
else {
Column() {
List({ space: 5, initialIndex: 0 }) {
ListItemGroup({ header: this.itemHeadStu('sid', 'sname', 'ssex', 'sage', 'sclass') }) {
ForEach(this.list1, (item: Student,index) => {
ListItem() {
Row() {
Column(){
Text(item.sid.toString())
.fontSize(10)
.padding(5)
.width(70)
}
.justifyContent(FlexAlign.SpaceAround)
Column(){
Text(item.sname)
.fontSize(10)
.padding(5)
.width(70)
}
.justifyContent(FlexAlign.SpaceAround)
Column(){
Text(item.ssex)
.fontSize(10)
.padding(5)
.width(30)
}
.justifyContent(FlexAlign.SpaceAround)
Column(){
Text(item.sage.toString())
.fontSize(10)
.padding(5)
.width(30)
}
.justifyContent(FlexAlign.SpaceAround)
Column(){
Text(item.sclass.toString())
.fontSize(10)
.padding(5)
.width(50)
}
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
}
})
}
}
.sticky(StickyStyle.Header)
.height('50%')
.listDirection(Axis.Vertical)
.scrollBar(BarState.Auto)
.backgroundColor('#f0f5fa')
}
.margin({ top: 5 })
}
}
.height('30%')
// course表
Column() {
// 表头行
Row({space:10}) {
//表头
Column() {
Text(' course ')
.fontSize(20)
.backgroundColor('#f0f5fa')
.fontColor('#838eb0')
.borderColor('#b9c7da')
}
// 装载
Column() {
Text('装载')
.fontColor(Color.White)
.fontSize(12)
.padding(4)
.backgroundColor('#378dfc')
.onClick(() => {
this.flagCou=true
RdbUtils.queryAllCourse()
.then((courses: Array<Course>) => {
this.list2 = courses
}).catch((error) => {
openDialog('error' + error.toString())
})
})
}
}
.padding(5)
// 表单内容行
if (this.flagCou==true) {
Scroll() {
Column() {
List({ space: 5, initialIndex: 0 }) {
ListItemGroup({ header: this.itemHeadCou('cid', 'cname', 'chours', 'credit') }) {
ForEach(this.list2, (item: Course) => {
ListItem() {
Row() {
Column() {
Text(item.cid.toString())
.fontSize(10)
.padding(5)
.width(30)
}
.justifyContent(FlexAlign.SpaceAround)
Column() {
Text(item.cname)
.fontSize(10)
.padding(5)
.width(100)
}
.justifyContent(FlexAlign.Center)
Column() {
Text(item.chours.toString())
.fontSize(10)
.padding(5)
.width(80)
}
.justifyContent(FlexAlign.SpaceAround)
Column() {
Text(item.credit.toString())
.fontSize(10)
.padding(5)
.width(30)
}
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
}
})
}
}
.sticky(StickyStyle.Header)
.height('50%')
.listDirection(Axis.Vertical)
.scrollBar(BarState.Auto)
.backgroundColor('#f0f5fa')
}
.margin({ top: 1 })
}
.scrollable(ScrollDirection.Horizontal)
}
else{
Column() {
List({ space: 5, initialIndex: 0 }) {
ListItemGroup({ header:this.itemHeadCou('cid','cname','chours','credit') }){
ForEach(this.list2, (item: Course) => {
ListItem() {
Row(){
Column(){
Text(item.cid.toString())
.fontSize(10)
.padding(5)
.width(30)
}
.justifyContent(FlexAlign.SpaceAround)
Column(){
Text(item.cname)
.fontSize(10)
.padding(5)
.width(60)
}
.justifyContent(FlexAlign.Center)
Column(){
Text(item.chours.toString())
.fontSize(10)
.padding(5)
.width(80)
}
.justifyContent(FlexAlign.SpaceAround)
Column(){
Text(item.credit.toString())
.fontSize(10)
.padding(5)
.width(30)
}
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
}
})
}
}
.sticky(StickyStyle.Header)
.height('50%')
.listDirection(Axis.Vertical)
.scrollBar(BarState.Auto)
.backgroundColor('#f0f5fa')
}
.margin({top:1})
}
}
.height('30%')
// sc表
Column() {
Row({space:10}) {
Column() {
Column() {
Text(' sc ')
.fontSize(20)
.backgroundColor('#f0f5fa')
.fontColor('#838eb0')
.borderColor('#b9c7da')
}
}
Column() {
Text('装载')
.fontColor(Color.White)
.fontSize(12)
.padding(4)
.backgroundColor('#378dfc')
.onClick(() => {
RdbUtils.queryAllSc()
.then((scs: Array<Sc>) => {
this.list3 = scs
}).catch((error) => {
openDialog('error' + error.toString())
})
})
}
}
.padding(5)
Column() {
Column() {
List({ space: 5, initialIndex: 0 }) {
ListItemGroup({ header:this.itemHeadSc(' sid',' cid','score') }){
ForEach(this.list3, (item: Sc) => {
ListItem() {
Row(){
Column(){
Text(item.sid.toString())
.fontSize(10)
.padding(5)
.width(80)
}
.justifyContent(FlexAlign.SpaceAround)
Column(){
Text(item.cid.toString())
.fontSize(10)
.padding(5)
.width(30)
}
.justifyContent(FlexAlign.SpaceAround)
Column(){
Text(item.score.toString())
.fontSize(10)
.padding(5)
.width(30)
}
.justifyContent(FlexAlign.SpaceAround)
}
.justifyContent(FlexAlign.SpaceAround)
}
})
}
}
.sticky(StickyStyle.Header)
.height('40%')
.listDirection(Axis.Vertical)
.scrollBar(BarState.Auto)
.backgroundColor('#f0f5fa')
}
}
}
.height('40%')
}
}
}
function openDialog(text: string) {
AlertDialog.show(
{
title: 'title',
message: text,
autoCancel: true,
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: -20 },
}
)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,61 +0,0 @@
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';
import relationalStore from '@ohos.data.relationalStore'; // 导入模块
import RdbUtils from '../common/rdbUtils/RdbUtils';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
const STORE_CONFIG = {
name: 'RdbTest.db', // 数据库文件名
securityLevel: relationalStore.SecurityLevel.S1 // 数据库安全级别
};
relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, store) => {
if (err) {
console.error(`Failed to get RdbStore. Code:${err.code}, message:${err.message}`);
return;
}
console.info(`Succeeded in getting RdbStore.`);
//保存store, 方便后面我们对数据库的操作
RdbUtils.setStore(store)
});
}
onWindowStageDestroy(): void {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}

View File

@ -1,249 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import relationalStore from '@ohos.data.relationalStore'; // 导入模块
import Student from '../common/rdbUtils/student'
import RdbUtils from '../common/rdbUtils/RdbUtils';
import Sc from '../common/rdbUtils/sc'
import Course from '../common/rdbUtils/course';
import { SQLGenerator } from '../common/rdbUtils/RdbUtils';
import { left } from '../components/left';
import { right } from '../components/right';
import ThreeTable from '../common/rdbUtils/ThreeTable';
const last_names = "李,王,张,刘,陈,杨,黄,赵,周,吴,徐,孙,朱,马,胡,郭,林,何,高,梁,郑,罗,宋,谢,唐,韩,曹,许,邓,萧,冯,曾,程,蔡,彭,潘,袁,于,董,余,苏,叶,吕,魏,蒋,田,杜,丁,沈,姜,范,江,傅,钟,卢,汪,戴,崔,任,陆,廖,姚,方,金,邱,夏,谭,韦,贾,邹,石,熊,孟,秦,阎,薛,侯,雷,白,龙,段,郝,孔,邵,史,毛,常,万,顾,赖,武,康,贺,严,尹,钱,施,牛,洪,龚";
const last_names_list = last_names.split('');
const course_names = "语文、数学、外语、历史、思想政治、地理、 化学、物理、生物、体育、美术、音乐、技术、微积分、体育、毛泽东思想概论、思想道德修养、高等数学、线性代数、概率论与数理统计、离散数学、计算机原理、人工智能、程序设计基础、面向对象程序设计、数字逻辑电路、电路电子技术、数据结构与算法、WEB程序设计、计算机组成与结构、操作系统、数据库系统原理、编译原理、计算机网络"
const course_names_list = course_names.split("、")
const sidList = [];
const cidList = [];
const MAXAGE = 35;
const MINAGE = 15;
const MAXSCORE = 100;
let NUM = 1;
let CLASSID = 1;
let CLASSNUM = 1;
let issex:boolean = false;
let array1 : any = [];
let array2 : any = [];
let array3 : any = [];let t = 0;
function studentRandomRecord() {
for (let i = 0; i < 500; i++) {
const sid = `${2024}${String(NUM).padStart(4, '0')}`;
const sname = `${last_names_list[Math.floor(Math.random() * last_names_list.length)]}${sid}`;
const ssex = issex ? '男' : '女';
const sage = Math.random() * (MAXAGE - MINAGE) + MINAGE;
const sclass = `${2024}${String(CLASSID).padStart(2, '0')}`;
array1.push({
sid,
sname,
ssex,
sage,
sclass
})
const obj1:any = array1[i]
const valueBucket = {
'SID': obj1.sid,
'SNAME': obj1.sname,
'SSEX': obj1.ssex,
'SAGE': obj1.sage,
'SCLASS': obj1.sclass,
};
RdbUtils.insert('Student', valueBucket)
.then(() => {
})
sidList.push(sid);
if (CLASSNUM === 30) {
CLASSID++;
CLASSNUM = 1;
}
issex = !issex;
NUM++;
CLASSNUM++;
}
}
function courseRandomRecord() {
// hours=8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128,136,144,152,160,168,176,184,192
const chourss = Array.from({ length: 24 }, (_, i) => 8 * (i + 1));
for (let i = 0; i < 50; i++) {
const cid = String(i + 1).padStart(3, '0');
const cname = course_names_list[Math.floor(Math.random() * course_names_list.length)];
const chours = chourss[Math.floor(Math.random() * chourss.length)];
const credit = (chours / 16).toFixed(2);
array2.push({
cid,
cname,
chours,
credit
})
const obj2:any = array2[i]
const valueBucket2 = {
'CID': obj2.cid,
'CNAME': obj2.cname,
'CHOURS': obj2.chours,
'CREDIT': obj2.credit
};
RdbUtils.insert('Course', valueBucket2)
.then(() => {
})
cidList.push(cid);
}
}
function scRandomRecord() {
for (let i = 0; i < sidList.length; i++) {
for (let j = 0; j < 4; j++) {
const sid = sidList[i];
const cid = cidList[j];
const score = Math.random() * MAXSCORE;
array3.push({
sid,
cid,
score
})
const obj3:any = array3[t]
const valueBucket3 = {
'SID': obj3.sid,
'CID': obj3.cid,
'SCORE': obj3.score
};
RdbUtils.insert('Sc', valueBucket3)
.then(() => {
})
t++;
}
}
}
@Entry
@Component
struct Index {
@State SQLGenerator:SQLGenerator = new SQLGenerator()
@State list1:Array<Student> = [];
@State list2:Array<Course> = [];
@State list3:Array<Sc> = [];
@State list4:Array<Student> = [];
@State list5:Array<Course> = [];
@State list6:Array<Sc> = [];
@State list7:Array<ThreeTable> = [];
build() {
Row() {
Column({space:5}) {
left({list1: $list1, list2:$list2, list3:$list3});
}
.width('20%')
.padding(10)
Column() {
right({ SQLGenerator: $SQLGenerator, list4: $list4, list5:$list5, list6:$list6, list7:$list7});
}
.width('80%')
}
.alignItems(VerticalAlign.Top)
.backgroundColor("#d9e3f1")
.height('100%')
}
aboutToAppear() {
this.initStudentTable();
this.initCourseTable();
this.initScTable();
}
initStudentTable() {
const SQL_CREATE_TABLE_Student = 'CREATE TABLE IF NOT EXISTS Student' +
' (SID INTEGER PRIMARY KEY, ' +
'SNAME TEXT NOT NULL, ' +
'SSEX TEXT NOT NULL, ' +
'SAGE INTEGER, ' +
'SCLASS INTEGER)'; // 建Student表Sql语句
RdbUtils.executeSql(SQL_CREATE_TABLE_Student)
.then(() =>{
console.log('successfully created table_Student');
}).catch((err) => {
openDialog(err);
})
studentRandomRecord();
}
initCourseTable() {
const SQL_CREATE_TABLE_Course = 'CREATE TABLE IF NOT EXISTS Course' +
' (CID INTEGER PRIMARY KEY, ' +
'CNAME TEXT NOT NULL, ' +
'CHOURS INTEGER, ' +
'CREDIT INTEGER)'; // 建Course表Sql语句
RdbUtils.executeSql(SQL_CREATE_TABLE_Course)
.then(() =>{
console.log('successfully created table_Course');
}).catch((err) => {
openDialog(err);
})
courseRandomRecord();
}
initScTable() {
const SQL_CREATE_TABLE_SC = 'CREATE TABLE IF NOT EXISTS Sc' +
'(SID INTEGER, ' +
'CID INTEGER, ' +
'SCORE INTEGER, ' +
'PRIMARY KEY (SID, CID))'; // 建Sc表Sql语句
RdbUtils.executeSql(SQL_CREATE_TABLE_SC)
.then(() =>{
console.log('successfully created table_SC');
}).catch((err) => {
openDialog(err);
})
scRandomRecord()
}
}
function openDialog(text: string) {
AlertDialog.show(
{
title: 'title',
message: text,
autoCancel: true,
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: -20 },
}
)
}

View File

@ -1,28 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
@Entry
@Component
struct Page {
@State message: string = 'Hello World'
/**
* In low-code mode, do not add anything to the build function, as it will be
* overwritten by the content generated by the .visual file in the build phase.
*/
build() {
}
}

View File

@ -1,35 +0,0 @@
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": ["default","tablet"],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ts",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon" : "$media:startIcon",
"startWindowBackground" : "$color:start_window_background"
,
"exported": true
,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}]
}
}

View File

@ -1,8 +0,0 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -1,14 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
}
,{
"name": "EntryAbility_desc",
"value": "description"
},{
"name": "EntryAbility_label",
"value": "label"
}]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,5 +0,0 @@
{
"src": [
"pages/Index"
]
}

View File

@ -1,14 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
}
,{
"name": "EntryAbility_desc",
"value": "description"
},{
"name": "EntryAbility_label",
"value": "label"
}]
}

View File

@ -1,14 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
}
,{
"name": "EntryAbility_desc",
"value": "description"
},{
"name": "EntryAbility_label",
"value": "label"
}]
}

View File

@ -1,35 +0,0 @@
import hilog from '@ohos.hilog';
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function abilityTest() {
describe('ActsAbilityTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
})
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
})
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
})
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
})
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
})
})
}

View File

@ -1,5 +0,0 @@
import abilityTest from './Ability.test';
export default function testsuite() {
abilityTest();
}

View File

@ -1,50 +0,0 @@
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import hilog from '@ohos.hilog';
import { Hypium } from '@ohos/hypium';
import testsuite from '../test/List.test';
import window from '@ohos.window';
import Want from '@ohos.app.ability.Want';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
export default class TestAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator;
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs;
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments();
hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
windowStage.loadContent('testability/pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
}
onForeground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
}
onBackground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
}
}

View File

@ -1,17 +0,0 @@
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}

View File

@ -1,47 +0,0 @@
import hilog from '@ohos.hilog';
import TestRunner from '@ohos.application.testRunner';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import Want from '@ohos.app.ability.Want';
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator | undefined = undefined
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs | undefined = undefined
async function onAbilityCreateCallback() {
hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
}
async function addAbilityMonitorCallback(err : Error) {
hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
}
export default class OpenHarmonyTestRunner implements TestRunner {
constructor() {
}
onPrepare() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
}
async onRun() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
const bundleName = abilityDelegatorArguments.bundleName;
const testAbilityName = 'TestAbility';
let lMonitor: AbilityDelegatorRegistry.AbilityMonitor = {
abilityName: testAbilityName,
onAbilityCreate: onAbilityCreateCallback,
};
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
const want: Want = {
bundleName: bundleName,
abilityName: testAbilityName
};
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.startAbility(want, (err, data) => {
hilog.info(0x0000, 'testTag', 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
hilog.info(0x0000, 'testTag', 'startAbility : data : %{public}s',JSON.stringify(data) ?? '');
})
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
}
}

View File

@ -1,34 +0,0 @@
{
"module": {
"name": "entry_test",
"type": "feature",
"description": "$string:module_test_desc",
"mainElement": "TestAbility",
"deviceTypes": ["default","tablet"],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:test_pages",
"abilities": [
{
"name": "TestAbility",
"srcEntry": "./ets/testability/TestAbility.ets",
"description": "$string:TestAbility_desc",
"icon": "$media:icon",
"label": "$string:TestAbility_label",
"exported": true,
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"skills": [
{
"actions": [
"action.system.home"
],
"entities": [
"entity.system.home"
]
}
]
}
]
}
}

View File

@ -1,8 +0,0 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -1,16 +0,0 @@
{
"string": [
{
"name": "module_test_desc",
"value": "test ability description"
},
{
"name": "TestAbility_desc",
"value": "the test ability"
},
{
"name": "TestAbility_label",
"value": "test label"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -1,5 +0,0 @@
{
"src": [
"testability/pages/Index"
]
}

View File

@ -1,5 +0,0 @@
import localUnitTest from './LocalUnit.test';
export default function testsuite() {
localUnitTest();
}

View File

@ -1,33 +0,0 @@
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function localUnitTest() {
describe('localUnitTest',() => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
});
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
});
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
});
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
});
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
});
});
}

View File

@ -1,18 +0,0 @@
{
"hvigorVersion": "3.0.9",
"dependencies": {
"@ohos/hvigor-ohos-plugin": "3.0.9"
},
"execution": {
// "daemon": true, /* Enable daemon compilation. Default: true */
// "incremental": true, /* Enable incremental compilation. Default: true */
// "parallel": true, /* Enable parallel compilation. Default: true */
// "typeCheck": false, /* Enable typeCheck. Default: false */
},
"logging": {
// "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
},
"debugging": {
// "stacktrace": false /* Disable stacktrace compilation. Default: false */
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,6 +0,0 @@
import { appTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}

View File

@ -1,48 +0,0 @@
#!/bin/bash
# ----------------------------------------------------------------------------
# Hvigor startup script, version 1.0.0
#
# Required ENV vars:
# ------------------
# NODE_HOME - location of a Node home dir
# or
# Add /usr/local/nodejs/bin to the PATH environment variable
# ----------------------------------------------------------------------------
HVIGOR_APP_HOME="`pwd -P`"
HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js
warn() {
echo ""
echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
error() {
echo ""
echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
fail() {
error "$@"
exit 1
}
# Determine node to start hvigor wrapper script
if [ -n "${NODE_HOME}" ];then
EXECUTABLE_NODE="${NODE_HOME}/bin/node"
if [ ! -x "$EXECUTABLE_NODE" ];then
fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed"
fi
else
EXECUTABLE_NODE="node"
which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path"
fi
# Check hvigor wrapper script
if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then
fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}"
fi
# start hvigor-wrapper script
exec "${EXECUTABLE_NODE}" \
"${HVIGOR_WRAPPER_SCRIPT}" "$@"

View File

@ -1,64 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Hvigor startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js
set NODE_EXE=node.exe
goto start
:start
@rem Find node.exe
if defined NODE_HOME goto findNodeFromNodeHome
%NODE_EXE% --version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:findNodeFromNodeHome
set NODE_HOME=%NODE_HOME:"=%
set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE%
if exist "%NODE_EXE_PATH%" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:execute
@rem Execute hvigor
"%NODE_EXE%" "%WRAPPER_MODULE_PATH%" %*
if "%ERRORLEVEL%" == "0" goto hvigorwEnd
:fail
exit /b 1
:hvigorwEnd
if "%OS%" == "Windows_NT" endlocal
:end

View File

@ -1,13 +0,0 @@
{
"lockfileVersion": 1,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {
"@ohos/hypium@1.0.11": "@ohos/hypium@1.0.11"
},
"packages": {
"@ohos/hypium@1.0.11": {
"resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.11.tgz",
"integrity": "sha512-KawcLnv43C3QIYv1UbDnKCFX3MohtDxGuFvzlUxT/qf2DBilR56Ws6zrj90LdH6PjloJQwOPESuBQIHBACAK7w=="
}
}
}

View File

@ -1,12 +0,0 @@
{
"license": "",
"devDependencies": {
"@ohos/hypium": "1.0.11"
},
"author": "",
"name": "database13",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

View File

@ -1,21 +0,0 @@
# datafiting
### 1、项目说明
总体思路曲线拟合绘制程序项目开发的总体思路如图所示以实现交互界面与交互控制和数据结构和数值分析算法等。程序有两个主体功能1对设置的数据集和用户选择的拟合曲线类型进行拟合并计算出拟合优度和函数表达式2根据拟合得到的函数表达式进行绘制。
图1.1 项目开发的总体思路图
<img src="figs/overall.png" width=80% /></center>
### 2、开发环境说明
1系统版本OpenHarmony 4.0 Release
2SDK版本API 10
3Model类型Stage
4DevEco Studio版本Deveco Studio 4.0 release
5硬件环境Unionpi Whale、RK3566开发板
6预览器参数(1)DeviceType:default;(2)Resolution:560-1280;(3)DPI:240;其余参数自定。
### 3、项目主要函数调用关系图与项目输出界面演进图
图3.1 项目主要函数调用关系图
<img src="figs/relation.png" width=80% /></center>
图3.2 项目输出界面演进图
<img src="figs/evolution.png" width=80% /></center>

View File

@ -1,11 +0,0 @@
/node_modules
/oh_modules
/local.properties
/.idea
**/build
/.hvigor
.cxx
/.clangd
/.clang-format
/.clang-tidy
**/.test

View File

@ -1,10 +0,0 @@
{
"app": {
"bundleName": "com.test.myapplication",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}

View File

@ -1,8 +0,0 @@
{
"string": [
{
"name": "app_name",
"value": "MyApplication"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,49 +0,0 @@
{
"app": {
"signingConfigs": [
{
"name": "default",
"material": {
"certpath": "C:\\Users\\nInse\\.ohos\\config\\openharmony\\auto_ohos_default_draw2_com.test.myapplication.cer",
"storePassword": "0000001B23074682D90DCDA10157D8187E84EC05F50638D319B2E510345811D5FEB541650A0415030813F5",
"keyAlias": "debugKey",
"keyPassword": "0000001B291E996BCAB68900B133F9F5D394B9749AFD0C20146A22CE85070C1340F65B45506D15A417CC08",
"profile": "C:\\Users\\nInse\\.ohos\\config\\openharmony\\auto_ohos_default_draw2_com.test.myapplication.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "C:\\Users\\nInse\\.ohos\\config\\openharmony\\auto_ohos_default_draw2_com.test.myapplication.p12"
}
}
],
"products": [
{
"name": "default",
"signingConfig": "default",
"compileSdkVersion": 10,
"compatibleSdkVersion": 10,
"runtimeOS": "OpenHarmony",
}
],
"buildModeSet": [
{
"name": "debug",
},
{
"name": "release"
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}

View File

@ -1,6 +0,0 @@
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test

View File

@ -1,31 +0,0 @@
{
"apiType": "stageMode",
"buildOption": {
"arkOptions": {
// "apPath": "./modules.ap" /* Profile used for profile-guided optimization (PGO), a compiler optimization technique to improve app runtime performance. */
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": [
"./obfuscation-rules.txt"
]
}
}
}
},
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest",
}
]
}

View File

@ -1,6 +0,0 @@
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
}

View File

@ -1,18 +0,0 @@
# Define project specific obfuscation rules here.
# You can include the obfuscation configuration files in the current module's build-profile.json5.
#
# For more details, see
# https://gitee.com/openharmony/arkcompiler_ets_frontend/blob/master/arkguard/README.md
# Obfuscation options:
# -disable-obfuscation: disable all obfuscations
# -enable-property-obfuscation: obfuscate the property names
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
# -compact: remove unnecessary blank spaces and all line feeds
# -remove-log: remove all console.* statements
# -print-namecache: print the name cache that contains the mapping from the old names to new names
# -apply-namecache: reuse the given cache file
# Keep options:
# -keep-property-name: specifies property names that you want to keep
# -keep-global-name: specifies names that you want to keep in the global scope

View File

@ -1,10 +0,0 @@
{
"license": "",
"devDependencies": {},
"author": "",
"name": "entry",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -1,46 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export class COMMON_VALUE{
/**
* 字体大小(大)
*/
static readonly BIG_SIZE_FONT = 20
/**
* 字体大小(小)
*/
static readonly SMALL_SIZE_FONT = 15
/**
* 字体大小(超小)
*/
static readonly SMALLER_SIZE_FONT = 10
/**
* 浅蓝
*/
static readonly LIGHT_BLUE = '#87BAD4'
/**
* 紫色
*/
static readonly PURPLE = '#BE4AD9'
/**
* 灰色
*/
static readonly GREY = '#B8B8B8'
/**
* 浅白
*/
static readonly LIGHT_WHITE = '#F2F2F2'
}

View File

@ -1,237 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import promptAction from '@ohos.promptAction'
import { COMMON_VALUE } from '../common/commonValue'
import { handle } from '../utils/algorithm/createPotGather'
import { BoardInfo, Quadrant } from '../utils/drawBoard/BoardType'
import { IPoint, PointType } from '../utils/drawBoard/DrawPoint'
import { funcInfo, functionUtilIns } from '../utils/FunctionUtil'
@Component
export struct controlBar {
@State func:funcInfo|undefined = undefined
//TODO
@Prop fitFuncList:Array<funcInfo>
@Prop selectFitFunc:funcInfo
@Prop curFuncIndex:number
@Link isStartFit:boolean
@Link isShowFunc:boolean
@Link quadrant:Quadrant
@Link points:Array<IPoint>
@Link selectFuncIndex:number
@Consume board:BoardInfo
@Consume isRefreshPoint:boolean
@Consume isRefreshFunc:boolean
controller:CustomDialogController = new CustomDialogController({
builder:addPoints({points:$points,isStartFit:$isStartFit,isShowFunc:$isShowFunc})
})
build() {
Column(){
Row({space:5}){
Row(){
Text('坐标轴')
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
Radio({value:"四象限",group:"Quadrant"})
.checked(this.quadrant == Quadrant.FOUR)
.onClick(()=>{
this.quadrant = Quadrant.FOUR
AppStorage.setOrCreate("quadrant",Quadrant.FOUR)
})
Text('四象限')
.fontSize(COMMON_VALUE.SMALLER_SIZE_FONT)
Radio({value:"一象限",group:"Quadrant"})
.checked(this.quadrant == Quadrant.ONE)
.onClick(()=>{
this.quadrant = Quadrant.ONE
AppStorage.setOrCreate("quadrant",Quadrant.ONE)
})
Text('一象限')
.fontSize(COMMON_VALUE.SMALLER_SIZE_FONT)
}.backgroundColor(COMMON_VALUE.GREY)
Row({space:5}){
Button('生成数据集')
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
.type(ButtonType.Normal)
.onClick(()=>{
this.isRefreshPoint = !this.isRefreshPoint
this.points = this.board.initMap()
this.board.drawAxis()
this.board.drawPoints()
})
Button('显示数据集')
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
.type(ButtonType.Normal)
.onClick(()=>{
this.isShowFunc = false
})
Button('显示数据集与曲线')
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
.type(ButtonType.Normal)
.onClick(()=>{
if(this.points.length == 0){
promptAction.showToast({
message:"还未选择样本点!"
})
return
}
if(this.selectFuncIndex != this.curFuncIndex){
this.isShowFunc = false
this.selectFuncIndex = this.curFuncIndex
}
setTimeout(()=>{
this.isStartFit = false
if (this.isShowFunc == false) {
this.isShowFunc = true
}
},100)
})
Button('手动输入数据集')
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
.type(ButtonType.Normal)
.onClick(()=>{
this.controller.open()
})
Button('拟合')
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
.type(ButtonType.Normal)
.onClick(()=>{
if(this.points.length == 0){
promptAction.showToast({
message:"还未选择样本点!"
})
return
}
//TODO
this.selectFitFunc = this.fitFuncList[this.curFuncIndex]
this.func = functionUtilIns.getFitFunc(this.selectFitFunc,this.points)
this.isStartFit = true
this.isShowFunc = false
setTimeout(()=>{
this.isShowFunc = true
},100)
this.selectFuncIndex = this.curFuncIndex
})
}
}
Row(){
Text('结果输出:')
Swiper(){
if(this.isStartFit){
Text('函数形式:' + this.selectFitFunc.name + "\t" + this.selectFitFunc.body)
.width('100%').height('100%')
Text('函数系数:' + this.func!.body)
.width('100%').height('100%')
Text('拟合优度R^2:' + this.func!.R!)
.width('100%').height('100%')
}
}.backgroundColor(COMMON_VALUE.GREY).layoutWeight(1).vertical(true).height('100%').autoPlay(false).indicator(false).loop(false)
}.width('100%').layoutWeight(1).padding(5)
}.backgroundColor(COMMON_VALUE.LIGHT_WHITE).width('100%').height('100%')
}
}
@CustomDialog
struct addPoints{
controller:CustomDialogController
@State setNum:number = -1
@State num:number = 0
@State msg:string = ''
@Link points:Array<IPoint>
@Link isStartFit:boolean
@Link isShowFunc:boolean
@Consume board:BoardInfo
@Consume isRefreshPoint:boolean
@Consume isRefreshFunc:boolean
build(){
Column({space:5}){
Row(){
if(this.setNum == -1){
Text('设置样本点个数')
TextInput({text:this.num.toString()})
.onChange((value)=>{
this.num = Number(value)
})
}
}
if(this.setNum == -1){
Row(){
Button('确定')
.onClick(()=>{
if(this.num <= 0){
promptAction.showToast({
message:"必须为正整数"
})
return
}
this.points = []
this.setNum = this.num
})
.type(ButtonType.Normal)
Button('取消')
.onClick(()=>{
this.controller.close()
})
.type(ButtonType.Normal)
}.width('100%').justifyContent(FlexAlign.SpaceAround)
}else {
Column(){
if(this.setNum == 0){
Text('是否保存数据集')
}else{
Text("输入" + this.setNum + "个样本点,格式为X,X")
TextInput({text:this.msg})
.onChange((value)=>{
this.msg = value
})
}
Row(){
Button('确定')
.onClick(()=>{
if(this.setNum == 0){
this.isRefreshPoint = !this.isRefreshPoint
this.board.initMap(this.points)
this.board.drawAxis()
this.board.drawPoints()
this.controller.close()
}else{
let arr = this.msg.split(',')
this.points.push({x:Number(arr[0]),y:Number(arr[1]),pointType:PointType.CONTINUE})
this.msg = ''
this.setNum--
}
})
.type(ButtonType.Normal)
Button('取消')
.onClick(()=>{
this.controller.close()
})
.type(ButtonType.Normal)
}.width('100%').justifyContent(FlexAlign.SpaceAround)
}
}
}.padding(5)
}
}

View File

@ -1,118 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { COMMON_VALUE } from '../common/commonValue'
import { funcInfo } from '../utils/FunctionUtil'
@Component
export struct fitFuncType {
@Link fitFuncList:Array<funcInfo>
@Link curFuncIndex:number
controller:CustomDialogController = new CustomDialogController({
builder:addFitFuncType({fitFuncList:$fitFuncList})
})
build() {
Column({space:5}){
Text('拟合曲线类型')
.height('12%')
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
List(){
ForEach(this.fitFuncList,(item:funcInfo,index:number)=>{
ListItem(){
funcItem({curFuncIndex:$curFuncIndex,func:item,funcIndex:index})
}.width('100%').height(30)
})
}.width('100%').layoutWeight(1).backgroundColor(COMMON_VALUE.LIGHT_BLUE)
Button('新增拟合曲线类型')
.onClick(()=>{
this.controller.open()
})
.type(ButtonType.Normal)
.backgroundColor(COMMON_VALUE.PURPLE)
}.width('100%').height('100%').padding({top:5,bottom:5,right:5}).backgroundColor(COMMON_VALUE.LIGHT_WHITE)
}
}
@Component
struct funcItem {
@Link curFuncIndex:number
@Prop func:funcInfo
@Prop funcIndex:number
build() {
Row({space:5}){
Radio({value:this.func.name,group:"fitFunc"})
.width(20)
.height(20)
.checked(this.curFuncIndex == this.funcIndex)
.onChange((value)=>{
if(this.curFuncIndex == this.funcIndex){
return
}
this.curFuncIndex = this.funcIndex
})
Text(this.func.name)
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
Text(this.func.body)
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
}.width('100%').height('100%')
}
}
let funcList:Array<funcInfo> = [
{name:"对数函数",body:"a*log(x,b)+c"},
{name:"指数函数",body:"a*e^(0.01x)+b"}
]
@CustomDialog
struct addFitFuncType{
@Link fitFuncList:Array<funcInfo>
controller:CustomDialogController
@State index:number = 0
@Builder item(index:number){
Row(){
Text(funcList[index].name)
.fontColor(this.index == index?Color.Red:Color.Black)
Text(funcList[index].body)
.fontColor(this.index == index?Color.Red:Color.Black)
}.width('100%').onClick(()=>{
this.index = index
})
}
build(){
Column({space:5}){
ForEach(funcList,(item:funcInfo,index)=>{
this.item(index)
})
Row(){
Button('确定')
.onClick(()=>{
this.fitFuncList.push({name:funcList[this.index].name,body:funcList[this.index].body})
funcList.splice(this.index,1)
this.controller.close()
})
.type(ButtonType.Normal)
Button('取消')
.onClick(()=>{
this.controller.close()
})
.type(ButtonType.Normal)
}.width('100%').justifyContent(FlexAlign.SpaceAround)
}.width('100%').padding(5)
}
}

View File

@ -1,81 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { COMMON_VALUE } from '../common/commonValue'
import { BoardInfo } from '../utils/drawBoard/BoardType'
import { IPoint, PointType } from '../utils/drawBoard/DrawPoint'
import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';
import { createDocument } from '../model/createDocumentModel';
import buffer from '@ohos.buffer';
@Component
export struct header {
@State filePath:string = ''
@Link points:Array<IPoint>
@Link isStartFit:boolean
@Link isShowFunc:boolean
@Consume board:BoardInfo
@Consume isRefreshPoint:boolean
@Consume isRefreshFunc:boolean
context = getContext()
build() {
Row({space:5}){
Text('样本数据集文件')
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
Text(this.filePath)
.textOverflow({overflow:TextOverflow.MARQUEE})
.layoutWeight(1)
.fontSize(COMMON_VALUE.SMALL_SIZE_FONT)
.backgroundColor(COMMON_VALUE.LIGHT_BLUE)
.height('100%')
Button('装载')
.type(ButtonType.Normal)
.onClick(async ()=>{
this.points = []
let documentPicker = new picker.DocumentViewPicker()
let DocumentSelectOptions = new picker.DocumentSelectOptions();
let DocumentSelectResult: Array<string> = await documentPicker.select(DocumentSelectOptions)
let uri = DocumentSelectResult[0]
let file = fs.openSync(uri,fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
//已经获取到选择的文件 进行读取操作
let arrayBuffer = new ArrayBuffer(8)
let size = 0
let dSize = 0
let str = fs.readTextSync(file.path)
//解析路径
this.filePath = file.path
fs.closeSync(file)
//解析文件样本点
let arr = str.split('\n')
for (let index = 0; index < arr.length; index++) {
this.points.push({x:Number(arr[index].split(' ')[0]),y:Number(arr[index].split(' ')[1]),pointType:PointType.CONTINUE})
}
this.isStartFit = false
this.isShowFunc = false
this.isRefreshPoint = !this.isRefreshPoint
this.board.initMap(this.points)
this.board.drawPoints()
this.board.drawAxis()
})
}.width('100%').height('100%').padding(5).backgroundColor(COMMON_VALUE.LIGHT_WHITE)
}
}

View File

@ -1,47 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { BoardInfo, CONTEXT, FIT_CONTEXT } from '../utils/drawBoard/BoardType'
import { IPoint } from '../utils/drawBoard/DrawPoint'
import { funcInfo, functionUtilIns } from '../utils/FunctionUtil'
@Component
export struct imageShow {
@Prop loop_board:string
@Prop loop_fit:string
@Prop isShowFunc:boolean
@Prop points:Array<IPoint>
@Prop selectFitFunc:funcInfo
@Consume board:BoardInfo
@Consume isRefreshFunc:boolean
build() {
Stack(){
Canvas(CONTEXT)
.width('100%').height(this.loop_board)
if(this.isShowFunc){
Canvas(FIT_CONTEXT)
.width('100%').height(this.loop_fit)
.onReady(()=>{
//获取到经过拟合后的函数
functionUtilIns.getFitFunc(this.selectFitFunc,this.points)
//解析函数 获取对应坐标点
let points:Array<IPoint> = functionUtilIns.getPoints()
this.board.drawFitFunc(points)
})
}
}
}
}

View File

@ -1,43 +0,0 @@
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy(): void {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}

View File

@ -1,35 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import picker from '@ohos.file.picker';
import { BusinessError } from '@ohos.base';
import fs from '@ohos.file.fs';
/**
* 创建一个包含样本点的文件 用于读取测试
*/
export let createDocument = async ()=>{
let documentPicker = new picker.DocumentViewPicker();
let uris:Array<string> = []
let DocumentSaveOptions = new picker.DocumentSaveOptions();
DocumentSaveOptions.newFileNames = ['testPoints.txt']
uris = await documentPicker.save(DocumentSaveOptions)
let uri = uris[0]
let file = fs.openSync(uri, fs.OpenMode.WRITE_ONLY);
let writeLen = 0
writeLen += fs.writeSync(file.fd, '2 2\n100 100\n123 323\n200.99 199.999\n302.8 300.6\n400 400.9\n450 450');//todo必须加结束位 否则多读
fs.closeSync(file);
}

View File

@ -1,121 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { controlBar } from '../component/ControlBar'
import { fitFuncType } from '../component/FitFuncType'
import { header } from '../component/Header'
import { imageShow } from '../component/ImageShow'
import { createDocument } from '../model/createDocumentModel'
import { B1Q2D, B4Q2D, BoardInfo, Quadrant } from '../utils/drawBoard/BoardType'
import { IPoint } from '../utils/drawBoard/DrawPoint'
import { funcInfo } from '../utils/FunctionUtil'
@Entry
@Component
struct Index {
@State fitFuncList:Array<funcInfo> = [
{name:"一次函数",body:"a*x+b"},
{name:"二次函数",body:"a*x^2+b*x+c"},
{name:"三次函数",body:"a*x^3+b*x^2+c*x+d"},
{name:"四次函数",body:"a*x^4+b*x^3+c*x^2+d*x+e"}
]
@State curFuncIndex:number = 0
@State selectFuncIndex:number = 0
/**
* 是否开始拟合 点击拟合按钮改为true
* 响应:结果输出栏
*/
@State isStartFit:boolean = false
/**
* 是否展示拟合函数 点击显示数据集与曲线改为true
* 响应:出现函数图像
*/
@State isShowFunc:boolean = false
@State @Watch('refreshBoard')quadrant:Quadrant = Quadrant.FOUR
@Provide board:BoardInfo = B4Q2D
@Provide @Watch('refreshPoint')isRefreshPoint:boolean = false
@Provide @Watch('refreshFunc')isRefreshFunc:boolean = false
@State loop_board:string = '100%'
@State loop_fit:string = '100%'
@State virtualPoints:Array<IPoint> = []
@State boardPoints:Array<IPoint> = []
refreshPoint(){
if(this.loop_board == '100%'){
this.loop_board = '101%'
}else {
this.loop_board = '100%'
}
console.log('REFRESH point')
this.isStartFit = false
this.isShowFunc = false
}
refreshFunc(){
if(this.loop_fit == '100%'){
this.loop_fit = '101%'
}else {
this.loop_fit = '100%'
}
console.log('REFRESH func')
}
refreshBoard(){
console.log('REFRESH board')
if(this.quadrant == Quadrant.ONE){
this.board = B1Q2D
}else{
this.board = B4Q2D
}
if(this.virtualPoints.length != 0){
this.isRefreshPoint = !this.isRefreshPoint
this.isRefreshFunc = !this.isRefreshFunc
this.board.initMap(this.virtualPoints)
this.board.drawAxis()
this.board.drawPoints()
this.isStartFit = false
}
}
async aboutToAppear(){
await createDocument()
}
build() {
Column(){
Row(){
Column(){
header({points:$virtualPoints,isShowFunc:$isShowFunc,isStartFit:$isStartFit}).width('100%').height('15%')
imageShow({points:this.virtualPoints,selectFitFunc:this.fitFuncList[this.curFuncIndex],loop_board:this.loop_board,loop_fit:this.loop_fit,isShowFunc:this.isShowFunc}).width('100%').height('85%')
}.width('60%').height('100%')
fitFuncType({fitFuncList:$fitFuncList,curFuncIndex:$curFuncIndex}).width('40%').height('100%')
}.width('100%').height('75%')
//TODO
controlBar({points:$virtualPoints,isShowFunc:$isShowFunc,quadrant:$quadrant,isStartFit:$isStartFit,selectFitFunc:this.fitFuncList[this.selectFuncIndex],selectFuncIndex:$selectFuncIndex,curFuncIndex:this.curFuncIndex,fitFuncList:this.fitFuncList}).width('100%').layoutWeight(1)
}.width('100%').height('100%')
}
}

View File

@ -1,65 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { IPoint, PointType } from './drawBoard/DrawPoint'
import { handle } from './algorithm/createPotGather'
export interface funcInfo {
/**
* 名称
*/
name: string
/**
* 函数体
*/
body: string
/**
* 拟合优度
*/
R?: number
}
/**
* 提供函数拟合的方法
*/
class FunctionUtil {
/**
* 根据拟合函数类型和样本点计算出拟合函数
* 返回funcInfo
*/
getFitFunc(fitFunc: funcInfo, points: Array<IPoint>) {
handle.fit(fitFunc.body, points);
let func: funcInfo = { name: "", body: handle.fitFunc, R: handle.R_squared }
return func
}
/**
* 根据函数返回xyMap
*/
getPoints() {
//TODO 结合原代码
//用来测试的拟合函数
handle.compote_curveData();
let point: Array<IPoint> = handle.coordinatePoint;
// console.log(handle.fitFunc)
// for (let i = 0; i < point.length; i++) {
// console.log("testTag", "(" + point[i].x + ", " + point[i].y + ")");
// }
return point
}
}
export let functionUtilIns = new FunctionUtil()

View File

@ -1,175 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { mathjs } from './evaluate';
import {IPoint, PointType} from "../drawBoard/DrawPoint"
import {FitRes} from "./fittingResult"
import { Matrix } from './least_square';
import { Quadrant } from '../drawBoard/BoardType';
import { Exponent } from './exponentialFit';
import { Logarithm } from './logarithmicFit';
function arrange(low: number, high: number, step: number): number[] {
const rangeArray: number[] = [];
if (step <= 0) {
throw new Error("Step must be greater than zero.");
}
for (let i = low; i <= high; i += step) {
rangeArray.push(i);
}
return rangeArray;
}
const replaceVar: Array<string> = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
class CreatePointGather {
coordinatePoint: Array<IPoint>;
theta: number[];
error: number;
R_squared: number;
fitFunc: string;
funcFormat: string;
private m: number;
constructor() {
this.coordinatePoint = [];
this.theta = [];
this.error = 0;
this.R_squared = 0;
this.fitFunc = "";
this.funcFormat = "";
this.m = 0;
}
private judgeWhichM(funcFormat: string) {
const index = funcFormat.indexOf("^");
if (index === -1) {
this.m = 1;
} else {
this.m = Number(funcFormat[index + 1]);
}
}
private getFitFunc(funcFormat: string): void {
this.funcFormat = funcFormat;
this.fitFunc = funcFormat;
if (funcFormat == "a*e^(0.01x)+b") {
for (let i = 0; i < 2; i++) {
if (this.theta[i] < 0 && this.fitFunc[this.fitFunc.indexOf(replaceVar[i]) - 1] == "+") {
this.fitFunc = this.fitFunc.substring(0, this.fitFunc.indexOf(replaceVar[i]) - 1) + this.fitFunc.substring(this.fitFunc.indexOf(replaceVar[i]));
}
this.fitFunc = this.fitFunc.replace(replaceVar[i], this.theta[i].toFixed(4));
}
} else if (funcFormat == "a*log(x,b)+c") {
for (let i = 0; i < 3; i++) {
if (this.theta[i] < 0 && this.fitFunc[this.fitFunc.indexOf(replaceVar[i]) - 1] == "+") {
this.fitFunc = this.fitFunc.substring(0, this.fitFunc.indexOf(replaceVar[i]) - 1) + this.fitFunc.substring(this.fitFunc.indexOf(replaceVar[i]));
}
this.fitFunc = this.fitFunc.replace(replaceVar[i], this.theta[i].toFixed(4));
}
} else {
for (let i = 0; i < this.m + 1; i++) {
if (this.theta[i] < 0 && this.fitFunc[this.fitFunc.indexOf(replaceVar[i]) - 1] == "+") {
this.fitFunc = this.fitFunc.substring(0, this.fitFunc.indexOf(replaceVar[i]) - 1) + this.fitFunc.substring(this.fitFunc.indexOf(replaceVar[i]));
}
this.fitFunc = this.fitFunc.replace(replaceVar[i], this.theta[i].toFixed(4));
}
}
}
private calculate_function(x:number): number {
if (this.funcFormat == "a*e^(0.01x)+b") {
return Exponent.expFunc(x, this.theta[0], this.theta[1]);
} else if (this.funcFormat == "a*log(x,b)+c") {
if (x > 0) return Logarithm.logFunc(x, this.theta[0], this.theta[1], this.theta[2]);
else return Number.NaN;
}
return mathjs.evaluate(this.fitFunc, [{char: 'x', value: x}]);
}
compote_curveData(low: number = -500, high: number = 500, step: number = 1): Array<IPoint> {
if (AppStorage.get("quadrant") == Quadrant.ONE) {
low = 0;
high = 1000;
}
this.coordinatePoint = [];
let xValues = arrange(low, high, step);
let yValues: number[] = [];
let size = xValues.length;
yValues = Array<number>(size).fill(0).map((_, index) => {
return this.calculate_function(xValues[index]);
})
for (let i = 0; i < size; i++) {
if (!Number.isNaN(yValues[i])) {
this.coordinatePoint.push({
x: xValues[i],
y: yValues[i],
pointType: PointType.CONTINUE
});
}
}
if (!this.coordinatePoint.length) {
this.coordinatePoint.push({
x: 0,
y: 0,
pointType: PointType.CONTINUE
})
}
return this.coordinatePoint;
}
private error_func(sampleData: Array<IPoint>): FitRes {
let sx: number[] = sampleData.map(value => value.x);
let sy: number[] = sampleData.map(value => value.y);
let y_predict: number[] = Array<number>(sx.length).fill(0).map((_, index) => {
return this.calculate_function(sx[index]);
})
let error: number = 0;
for (let i = 0; i < sx.length; i++) {
error += (sy[i] - y_predict[i]) ** 2;
}
const mean = sy.reduce((acc, val) => acc + val, 0) / sy.length;
let sum: number = sy.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0);
let R_squared: number = 1 - (error/sum);
if (R_squared <= 0) R_squared = 0;
let fitRes: FitRes = {
error: error,
R_squared: R_squared
};
return fitRes;
}
fit(funcFormat: string, sampleData: Array<IPoint>): void {
let fitRes: FitRes = {};
if (funcFormat == "a*e^(0.01x)+b") {
this.theta = Exponent.gradientDescentExp(sampleData);
} else if (funcFormat == "a*log(x,b)+c") {
this.theta = Logarithm.gradientDescentLog(sampleData);
} else {
this.judgeWhichM(funcFormat);
fitRes = Matrix.leastSquareMethod(this.m, sampleData);
if (fitRes.theta) this.theta = fitRes.theta;
}
this.getFitFunc(funcFormat);
fitRes = this.error_func(sampleData);
if (fitRes.error && fitRes.R_squared) {
this.error = fitRes.error;
this.R_squared = fitRes.R_squared;
}
}
}
export let handle: CreatePointGather = new CreatePointGather();

View File

@ -1,224 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
interface replaceableVar {
char: string,
value: number
}
class MathExpressionParser {
private tokens: string[];
private currentTokenIndex: number;
private variables: replaceableVar[];
constructor() {
this.tokens = []
this.currentTokenIndex = 0
this.variables = []
}
private tokenize(expression: string): string[] {
const regex: RegExp = new RegExp("(\\d+\\.?\\d*|\\.\\d+|[a-zA-Z]+|\\S)", "g");
const originalTokens = expression.match(regex) || [];
const Tokens: string[] = [];
for (let i = 0; i < originalTokens.length; i++) {
Tokens.push(originalTokens[i]);
if (i < originalTokens.length - 1) {
const currentToken = originalTokens[i];
const nextToken = originalTokens[i + 1];
if ((this.isNumber(currentToken) && this.isVariable(nextToken)) ||
(this.isVariable(currentToken) && this.isVariable(nextToken)) ||
(currentToken === ')' && (this.isVariable(nextToken) || this.isNumber(nextToken))) ||
(this.isNumber(currentToken) && nextToken === '(') ||
(this.isVariable(currentToken) && nextToken === '(')) {
Tokens.push('*');
}
}
}
return Tokens;
}
private existInArr(token: string): number {
for (let i: number = 0; i < this.variables.length; i++) {
if (this.variables[i].char == token) {
return i;
}
}
return -1;
}
private isNumber(token: string): boolean {
const num = Number(token);
return !Number.isNaN(num) && Number.isFinite(num);
}
private isVariable(token: string): boolean {
const temp: RegExp = new RegExp("^[a-zA-Z]+$")
return temp.test(token) && !this.isFunction(token) && token !== "π";
}
private isFunction(token: string): boolean {
return ['pow', 'sin', 'cos', 'tan', 'ln', 'sqrt', 'log2', 'log10'].includes(token);
}
private getCurrentToken(): string {
return this.tokens[this.currentTokenIndex];
}
private getNextToken(): string {
this.currentTokenIndex++;
return this.getCurrentToken();
}
private parsePrimaryExpression(): number {
const token = this.getCurrentToken();
if (token === '(') {
this.getNextToken(); // consume '('
const result = this.parseExpression();
if (this.getCurrentToken() !== ')') {
throw new Error("Expected ')' after expression");
}
this.getNextToken(); // consume ')'
return result;
} else if (token === 'π') {
this.getNextToken(); // consume 'π'
return Math.PI;
} else if (this.isVariable(token)) {
if (this.existInArr(token) != -1) {
const value = this.variables[this.existInArr(token)].value;
this.getNextToken(); // consume variable
return value;
} else {
throw new Error(`Unknown variable: ${token}`);
}
} else if (this.isFunction(token)) {
return this.parseFunction();
} else {
const num = Number(token);
this.getNextToken(); // consume number
return num;
}
}
private parseFunction(): number {
const functionName = this.getCurrentToken();
this.getNextToken(); // consume function name
if (this.getCurrentToken() !== '(') {
throw new Error(`Expected '(' after function name ${functionName}`);
}
this.getNextToken(); // consume '('
const argument1 = this.parseExpression();
if (functionName === 'pow') {
if (this.getCurrentToken() !== ',') {
throw new Error(`Expected ',' between arguments for function ${functionName}`);
}
this.getNextToken(); // consume ','
const argument2 = this.parseExpression();
if (this.getCurrentToken() !== ')') {
throw new Error(`Expected ')' after arguments for function ${functionName}`);
}
this.getNextToken(); // consume ')'
return Math.pow(argument1, argument2);
}
if (this.getCurrentToken() !== ')') {
throw new Error(`Expected ')' after argument for function ${functionName}`);
}
this.getNextToken(); // consume ')'
switch (functionName) {
case 'sin':
return Math.sin(argument1);
case 'cos':
return Math.cos(argument1);
case 'tan':
return Math.tan(argument1);
case 'ln':
return Math.log(argument1);
case 'sqrt':
return Math.sqrt(argument1);
case 'log2':
return Math.log2(argument1);
case 'log10':
return Math.log10(argument1);
default:
throw new Error(`Unknown function: ${functionName}`);
}
}
private parseFactor(): number {
// 处理一元负号
if (this.getCurrentToken() === '-') {
this.getNextToken(); // consume '-'
return -this.parseFactor();
}
// 处理初级表达式
let result = this.parsePrimaryExpression();
// 处理乘法和除法
while (this.getCurrentToken() === '*' || this.getCurrentToken() === '/') {
const operator = this.getCurrentToken();
this.getNextToken(); // consume operator
const operand = this.parsePrimaryExpression();
if (operator === '*') {
result *= operand;
} else if (operator === '/') {
if (operand === 0) {
throw new Error("Division by zero");
}
result /= operand;
}
}
return result;
}
private parseExpression(): number {
let result = this.parseFactor();
while (this.getCurrentToken() === '+' || this.getCurrentToken() === '-') {
const operator = this.getCurrentToken();
this.getNextToken();
const operand = this.parseFactor();
if (operator === '+') {
result += operand;
} else if (operator === '-') {
result -= operand;
}
}
return result;
}
public evaluate(expression: string, variables: replaceableVar[] = []): number {
let temp: RegExp = new RegExp("\\s+", "g");
expression = expression.trim().replace(temp, "");
temp = new RegExp("(\\([^()]*?(?:\\([^()]*?\\)[^()]*?)*\\)|\\w+)(?:\\*\\*|\\^)(\\([^()]*?(?:\\([^()]*?\\)[^()]*?)*\\)|\\w+)", "g");
expression = expression.replace(temp, "pow($1, $2)");
this.tokens = this.tokenize(expression);
this.currentTokenIndex = 0;
this.variables = variables;
const result = this.parseExpression();
if (this.currentTokenIndex !== this.tokens.length) {
console.log("Token" + this.tokens);
console.log("当前index" + this.currentTokenIndex + " " + "当前length" + this.tokens.length);
throw new Error("Unexpected token");
}
return Number(result.toFixed(4));
}
}
export let mathjs: MathExpressionParser = new MathExpressionParser();

View File

@ -1,64 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {IPoint} from "../drawBoard/DrawPoint"
export class Exponent {
static expFunc(x: number, a: number, b: number): number {
return a * Math.exp(0.01 * x) + b;
}
/**
* 梯度下降法
* @param sampleData
* @param learningRate
* @param epochs
* @returns
*/
static gradientDescentExp(sampleData: Array<IPoint>, learningRate: number = 0.00001, epochs: number = 100000): number[] {
let a = 0.001; // 初始化参数
let b = 0.001;
for (let epoch = 0; epoch < epochs; epoch++) {
let aGrad = 0;
let bGrad = 0;
const n = sampleData.length;
for (let i = 0; i < n; i++) {
const x = sampleData[i].x;
const y = sampleData[i].y;
const yPredict = Exponent.expFunc(x, a, b);
aGrad += -2 * (y - yPredict) * Math.exp(0.01 * x);
bGrad += -2 * (y - yPredict);
}
a -= (aGrad / n) * learningRate;
b -= (bGrad / n) * learningRate;
// 检查参数是否过大或过小,若是则终止训练
if (Number.isNaN(a) || Number.isNaN(b) || !Number.isFinite(a) || !Number.isFinite(b) || Math.abs(a) > 1e10 || Math.abs(b) > 1e10) {
console.error(`Parameters became unstable at epoch ${epoch + 1}`);
break;
}
// 每1000个epoch打印一次当前参数
if (epoch % 1000 === 0) {
console.log(`Epoch ${epoch + 1}, a: ${a}, b: ${b}`);
}
}
return [a, b];
}
}

View File

@ -1,25 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* 拟合结果接口类型,包含拟合的函数系数和协方差矩阵
*/
export interface FitRes {
theta?: number[];
covarianceMatrix?: number[][];
error?: number;
R_squared?: number;
}

View File

@ -1,142 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {IPoint} from "../drawBoard/DrawPoint"
import {FitRes} from "./fittingResult"
/**
* 矩阵运算工具类
*/
export class Matrix {
/**
* 矩阵转置
* @param matrix
* @returns
*/
static transpose(matrix: number[][]): number[][] {
return matrix[0].map((_, colIndex) => matrix.map(row => row[colIndex]));
}
/**
* 矩阵乘法
* @param a
* @param b
* @returns
*/
static multiplyMatrices(a: number[][], b: number[][]): number[][] {
const result: number[][] = [];
for (let i = 0; i < a.length; i++) {
// result[i] = [];
result.push([]);
for (let j = 0; j < b[0].length; j++) {
let sum = 0;
for (let k = 0; k < b.length; k++) {
sum += a[i][k] * b[k][j];
}
// result[i][j] = sum;
result[i].push(sum);
}
}
return result;
}
/**
* 矩阵求逆
* @param matrix
* @returns
*/
static inverseMatrix(matrix: number[][]): number[][] {
const size = matrix.length;
const augmented = matrix.map((row, i) => [
...row,
...Array<number>(size).fill(0).map((_, j) => (i === j ? 1 : 0))
]);
for (let i = 0; i < size; i++) {
let maxRow = i;
for (let k = i + 1; k < size; k++) {
if (Math.abs(augmented[k][i]) > Math.abs(augmented[maxRow][i])) {
maxRow = k;
}
}
let temp = augmented[i];
augmented[i] = augmented[maxRow];
augmented[maxRow] = temp;
// [augmented[i], augmented[maxRow]] = [augmented[maxRow], augmented[i]];
const divisor = augmented[i][i];
for (let j = 0; j < augmented[0].length; j++) {
augmented[i][j] /= divisor;
}
for (let k = 0; k < size; k++) {
if (k !== i) {
const factor = augmented[k][i];
for (let j = 0; j < augmented[0].length; j++) {
augmented[k][j] -= factor * augmented[i][j];
}
}
}
}
return augmented.map(row => row.slice(size));
}
/**
* 最小二乘法
* @param m
* @param sampleData
* @returns
*/
static leastSquareMethod(m: number, sampleData: Array<IPoint>): FitRes {
const x = sampleData.map(d => d.x);
const y = sampleData.map(d => d.y);
const A = x.map(xi => {
const row: number[] = [];
for (let i = m; i >= 0; i--) {
row.push(Math.pow(xi, i));
}
return row;
});
const yVec = y.map(yi => [yi]);
const At = Matrix.transpose(A);
const AtA = Matrix.multiplyMatrices(At, A);
const Aty = Matrix.multiplyMatrices(At, yVec);
const invAtA = Matrix.inverseMatrix(AtA);
const theta = Matrix.multiplyMatrices(invAtA, Aty);
const residuals = yVec.map((yi, i) => [yi[0] - A[i].reduce((sum, aij, j) => sum + aij * theta[j][0], 0)]);
const residualsSquaredSum = residuals.reduce((sum, ri) => sum + ri[0] ** 2, 0);
const degreesOfFreedom = y.length - (m + 1);
const meanSquaredError = residualsSquaredSum / degreesOfFreedom;
const covarianceMatrix = invAtA.map(row => row.map(value => value * meanSquaredError));
const fitRes: FitRes = {
theta: theta.map(row => row[0]),
covarianceMatrix: covarianceMatrix
};
return fitRes;
}
}

View File

@ -1,81 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {IPoint} from "../drawBoard/DrawPoint"
import {Matrix} from "./least_square"
export class Logarithm {
static logFunc(x: number, a: number, b: number, c: number): number {
return a * Math.log(x) / Math.log(b) + c;
}
linearRegressionLog(sampleData: Array<IPoint>, base: number): number[] {
const A = sampleData.map((value) => [Math.log(value.x) / Math.log(base), 1]);
const y = sampleData.map((value) => value.y);
const At = Matrix.transpose(A);
const AtA = Matrix.multiplyMatrices(At, A);
const Aty = Matrix.multiplyMatrices(At, y.map(v => [v]));
const invAtA = Matrix.inverseMatrix(AtA);
const theta = Matrix.multiplyMatrices(invAtA, Aty);
const a: number = theta.map(row => row[0])[0];
const c: number = theta.map(row => row[0])[1];
return [ a, c ];
}
static gradientDescentLog(sampleData: Array<IPoint>, learningRate: number = 0.00001, epochs: number = 100000): number[] {
let a = 0.001; // 初始化参数
let b = 2; // 初始对数底数,需 > 0 且 ≠ 1
let c = 0.001;
const n = sampleData.length;
for (let epoch = 0; epoch < epochs; epoch++) {
let aGrad = 0;
let bGrad = 0;
let cGrad = 0;
for (let i = 0; i < n; i++) {
const x = sampleData[i].x;
const y = sampleData[i].y;
let yPredict = Logarithm.logFunc(x, a, b, c);
let logX = Math.log(x);
let logB = Math.log(b);
if (x > 0 && b > 0 && b != 1) {
yPredict = Logarithm.logFunc(x, a, b, c);
logX = Math.log(x);
logB = Math.log(b);
} else continue;
aGrad += -2 * (y - yPredict) * (logX / logB);
bGrad += -2 * (y - yPredict) * (-a * logX / (logB * logB) * (1 / b)); // 链式法则计算 b 的梯度
cGrad += -2 * (y - yPredict);
}
a -= (aGrad / n) * learningRate;
c -= (cGrad / n) * learningRate;
if (b - (bGrad / n) * learningRate <= 0) break;
else b -= (bGrad / n) * learningRate;
if (Number.isNaN(a) || Number.isNaN(b) || Number.isNaN(c)) {
console.error(`Parameters became NaN at epoch ${epoch + 1}`);
break;
}
}
return [ a, b, c ];
}
}

View File

@ -1,441 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { IPoint, PointType } from './DrawPoint';
//标准值
/**
* imageShow组件的大小(vp)
*/
export const I_WIDTH = 480;//3568 340
/**
* imageShow组件的大小(vp)
*/
export const I_HEIGHT = 250;//3568 160
/**
* 第一个X刻度对应的值
*/
const X_VALUE = 100
/**
* 第一个Y刻度对应的值
*/
const Y_VALUE = 100
export const SETTING:RenderingContextSettings = new RenderingContextSettings(true)
export const CONTEXT:CanvasRenderingContext2D = new CanvasRenderingContext2D(SETTING)
export const FIT_CONTEXT:CanvasRenderingContext2D = new CanvasRenderingContext2D(SETTING)
CONTEXT.font = '10px sans-serif'
export enum Quadrant{
ONE = 1,
FOUR = 4
}
export abstract class BoardInfo{
/**
* x刻度之间的像素距离
* 初始化后不允许修改
*/
XGapLen:number
/**
* y刻度之间的像素距离
* 初始化后不允许修改
*/
YGapLen:number
/**
* x刻度个数 (+)
* 初始化后不允许修改
*/
XCount:number
/**
* y刻度个数 (+)
* 初始化后不允许修改
*/
YCount:number
/**
* 原点的x坐标
* 初始化后不可修改
*/
X_centre:number = 0
/**
* 原点的y坐标
* 初始化后不可修改
*/
Y_centre:number = 0
/**
* canvas组件的margin (不包括箭头)
* 初始化后不可修改
*/
margin:number
/**
* 显示象限
* 初始化后不可修改
*/
quadrant:Quadrant
/**
* 画板的宽
* 初始化后不可修改
*/
width:number
/**
* 画板的高
* 初始化后不可修改
*/
height:number
//以下属性可修改
/**
* 单位X刻度对应的虚拟像素
* 根据倍数动态修正
*/
XUnit2vp:number
/**
* 单位Y刻度对应虚拟像素
* 根据倍数动态修正
*/
YUnit2vp:number
/**
* 第一个X刻度对应的值 (+)
* 根据倍数动态修正
*/
XValue:number = X_VALUE
/**
* 第一个Y刻度对应的值 (+)
* 根据倍数动态修正
*/
YValue:number = Y_VALUE
/**
* 虚拟点集
*/
virtualPoints:Array<IPoint> = []
/**
* 拟合后得到的函数的点集
*/
boardPoints:Array<IPoint> = []
constructor(margin:number,quadrant:Quadrant,Xgl:number,Ygl:number,XC:number,YC:number) {
this.margin = margin
this.quadrant = quadrant
//画板属性
this.width = I_WIDTH - 2 * this.margin
this.height = I_HEIGHT - 2 * this.margin
//定义单位刻度对应像素
this.XGapLen = Xgl
this.YGapLen = Ygl
this.XUnit2vp = Xgl/X_VALUE
this.YUnit2vp = Ygl/Y_VALUE
//定义个数
this.XCount = XC
this.YCount = YC
}
/**
* 绘制坐标轴
*/
public abstract drawAxis();
/**
* 设置画板上的xy数对
* 同时根据xy数对计算出合适的
*
* 初始化点集 需要保证xy都有赋值
*
* 返回virtualPoints
*/
public initMap(virtualPoints?:Array<IPoint>){
this.virtualPoints = []
if(virtualPoints){
this.virtualPoints = virtualPoints
}else{
let x = 0;
let y = 0
if(this.quadrant == Quadrant.ONE){
for (let index = 0; index < 20; index++) {
x = Math.random()*1000
y = Math.random()*1000
this.virtualPoints.push({x:x,y:y,pointType:PointType.CONTINUE})
}
}else{
for (let index = 0; index < 20; index++) {
x = ((Math.random()*2)-1)*500
y = ((Math.random()*2)-1)*500
this.virtualPoints.push({x:x,y:y,pointType:PointType.CONTINUE})
}
}
}
this.boardPoints = []
this.transToBoardPoints()
return this.virtualPoints
}
/**
* 绘制拟合函数
*/
public drawFitFunc(points:Array<IPoint>){
this.transToBoardPoints(points)
this.drawGraph(FIT_CONTEXT,points)
}
/**
* 绘制散点图
*/
public drawPoints(context:CanvasRenderingContext2D = CONTEXT,boardPoints:Array<IPoint> = this.boardPoints){
context.beginPath()
for (let index = 0; index < boardPoints.length; index++) {
context.fillRect(vp2px(boardPoints[index].x-1),vp2px(boardPoints[index].y-1),vp2px(1.5),vp2px(1.5))
}
context.stroke()
}
/**
* 绘制折线
*/
public drawGraph(context:CanvasRenderingContext2D = FIT_CONTEXT,boardPoints:Array<IPoint> = this.boardPoints){
FIT_CONTEXT.strokeStyle = 'red'
let isMeetDisContinue = false
let i = 0
while(boardPoints[i].pointType == PointType.DISCONTINUE && i <= boardPoints.length - 1){
i++
}
if(i == boardPoints.length){
//全间断点
return
}
if(i != 0){
context.fillRect(vp2px(boardPoints[i].x - 1),vp2px(boardPoints[i].y - 1),vp2px(1.5),vp2px(1.5))
}
context.moveTo(vp2px(boardPoints[i].x),vp2px(boardPoints[i].y))
//间断点画圆
for (let index = i + 1; index < boardPoints.length ; index++) {
if(boardPoints[index].pointType == PointType.DISCONTINUE){
isMeetDisContinue = true
continue
}
if(isMeetDisContinue){
context.moveTo(vp2px(boardPoints[index].x),vp2px(boardPoints[index].y))
context.fillRect(vp2px(boardPoints[index].x - 1),vp2px(boardPoints[index].y - 1),vp2px(1.5),vp2px(1.5))
isMeetDisContinue = false
}else{
context.lineTo(vp2px(boardPoints[index].x),vp2px(boardPoints[index].y))
}
}
context.stroke()
}
/**
* 将虚拟点集(二维)转变为画布点集
*/
protected transToBoardPoints(virtualPoints?:Array<IPoint>){
if(virtualPoints){
for (let index = 0; index < virtualPoints.length; index++) {
virtualPoints[index].x = this.getXPosition(virtualPoints[index].x)
virtualPoints[index].y = this.getYPosition(virtualPoints[index].y)
virtualPoints[index].pointType = virtualPoints[index].pointType
}
return
}
for (let index = 0; index < this.virtualPoints.length; index++) {
this.boardPoints.push({x:this.getXPosition(this.virtualPoints[index].x),y:this.getYPosition(this.virtualPoints[index].y),pointType:this.virtualPoints[index].pointType})
}
}
/**
* 将虚拟坐标转变为画布坐标x(二维)
*/
private getXPosition(x:number){
return this.X_centre + this.XUnit2vp*x
}
/**
* 将虚拟坐标转变为画布坐标x(二维)
*/
private getYPosition(y:number){
return this.Y_centre - this.YUnit2vp*y
}
}
class board4Q2D extends BoardInfo{
constructor() {
super(5,Quadrant.FOUR,43,21,5,5);//根据具体环境配置
this.X_centre = (2 * this.margin + this.width)/2
this.Y_centre = (2 * this.margin + this.height)/2
}
public drawAxis(){
CONTEXT.beginPath()
CONTEXT.moveTo(vp2px(this.margin),vp2px(this.Y_centre))
CONTEXT.lineTo(vp2px(this.width + this.margin),vp2px(this.Y_centre))
CONTEXT.lineTo(vp2px(this.width + this.margin),vp2px(this.Y_centre + 3))
CONTEXT.lineTo(vp2px(this.width + this.margin + 3),vp2px(this.Y_centre))
CONTEXT.lineTo(vp2px(this.width + this.margin),vp2px(this.Y_centre - 3))
CONTEXT.lineTo(vp2px(this.width + this.margin),vp2px(this.Y_centre))
CONTEXT.moveTo(vp2px(this.X_centre),vp2px(this.height + this.margin))
CONTEXT.lineTo(vp2px(this.X_centre),vp2px(this.margin))
CONTEXT.lineTo(vp2px(this.X_centre - 3),vp2px(this.margin))
CONTEXT.lineTo(vp2px(this.X_centre),vp2px(this.margin - 3))
CONTEXT.lineTo(vp2px(this.X_centre + 3),vp2px(this.margin))
CONTEXT.lineTo(vp2px(this.X_centre),vp2px(this.margin))
CONTEXT.fill()
CONTEXT.fillText("0",vp2px(this.X_centre + 2),vp2px(this.Y_centre + 15))
let valueX = this.X_centre - this.XValue * this.XUnit2vp * (this.XCount + 1)
let valueY = this.Y_centre + 6
let value = -this.XValue * this.XCount
let count = 2 * this.XCount
//绘制X轴
while(--count >= 0) {
valueX += this.XGapLen
if(value == 0){
value += this.XValue
valueX += this.XGapLen
}
CONTEXT.moveTo(vp2px(valueX),vp2px(this.Y_centre))
CONTEXT.lineTo(vp2px(valueX),vp2px(this.Y_centre - 5))
CONTEXT.fillText(value.toString(),vp2px(valueX - this.getXTextBias(value.toString()) - 6),vp2px(valueY + 7))
value += this.XValue
}
//绘制Y轴
valueX = this.X_centre
valueY = this.Y_centre + this.YValue * this.YUnit2vp * (this.YCount + 1)
value = -this.YValue * this.YCount
count = 2 * this.YCount
while(--count >= 0) {
valueY -= this.YGapLen
if(value == 0){
value += this.YValue
valueY -= this.YGapLen
}
CONTEXT.moveTo(vp2px(this.X_centre),vp2px(valueY))
CONTEXT.lineTo(vp2px(this.X_centre + 3),vp2px(valueY))
CONTEXT.fillText(value.toString(),vp2px(valueX - this.getYTextBias(value.toString()) + 15),vp2px(valueY + 5))
value += this.YValue
}
CONTEXT.stroke()
}
/**
* 获取修正后的X刻度对应的文本的显示横向偏移量
*/
private getXTextBias(value:string){
let bias = value.length
let flag = 1
if(value[0] == '-'){
flag = -2
}
return (bias * (bias - 1))/2 + 1 + flag * this.XGapLen/50 ;
}
/**
* 获取修正后的Y刻度对应的文本的显示横向偏移量
*/
private getYTextBias(value:string){
let bias = value.length
if(bias == 1){
return 1
}
return bias * 3.5 + 1;
}
}
class board1Q2D extends BoardInfo{
constructor() {
super(20,Quadrant.ONE,42,20,10,10);//根据具体环境配置
this.X_centre = this.margin
this.Y_centre = this.margin + this.height
}
public drawAxis(){
CONTEXT.beginPath()
CONTEXT.moveTo(vp2px(this.margin),vp2px(this.margin + this.height))
CONTEXT.lineTo(vp2px(this.margin),vp2px(this.margin))
CONTEXT.lineTo(vp2px(this.margin - 3),vp2px(this.margin))
CONTEXT.lineTo(vp2px(this.margin),vp2px(this.margin - 3))
CONTEXT.lineTo(vp2px(this.margin + 3),vp2px(this.margin))
CONTEXT.lineTo(vp2px(this.margin),vp2px(this.margin))
CONTEXT.fill()
CONTEXT.moveTo(vp2px(this.margin),vp2px(this.margin + this.height))
CONTEXT.lineTo(vp2px(this.margin + this.width),vp2px(this.margin + this.height))
CONTEXT.lineTo(vp2px(this.margin + this.width),vp2px(this.margin + this.height + 3))
CONTEXT.lineTo(vp2px(this.margin + this.width + 3),vp2px(this.margin + this.height))
CONTEXT.lineTo(vp2px(this.margin + this.width),vp2px(this.margin + this.height - 3))
CONTEXT.lineTo(vp2px(this.margin + this.width),vp2px(this.margin + this.height))
CONTEXT.fill()
CONTEXT.fillText("0",vp2px(this.X_centre - 10),vp2px(this.Y_centre + 10))
let valueX = this.X_centre
let valueY = this.Y_centre + 6
let value = this.XValue
let count = this.XCount
//x轴
while(--count >= 0) {
valueX += this.XGapLen
CONTEXT.moveTo(vp2px(valueX),vp2px(this.Y_centre))
CONTEXT.lineTo(vp2px(valueX),vp2px(this.Y_centre - 5))
CONTEXT.fillText(value.toString(),vp2px(valueX-this.getXTextBias(value.toString()) - 10),vp2px(valueY + 10))
value += this.XValue
}
//y轴
valueX = this.X_centre
valueY = this.Y_centre
value = this.YValue
count = this.YCount
while(--count >= 0) {
valueY -= this.YGapLen
if(value == 0){
value += this.YValue
valueY -= this.YGapLen
}
CONTEXT.moveTo(vp2px(this.X_centre),vp2px(valueY))
CONTEXT.lineTo(vp2px(this.X_centre + 5),vp2px(valueY))
CONTEXT.fillText(value.toString(),vp2px(valueX + 20 - this.getYTextBias(value.toString())),vp2px(valueY + 3))
value += this.YValue
}
CONTEXT.stroke()
}
/**
* 获取修正后的X刻度对应的文本的显示横向偏移量
*/
private getXTextBias(value:string){
let bias = value.length
let flag = 1
if(value[0] == '-'){
flag = -2
}
return (bias * (bias - 1))/2 + 1 + flag * this.XGapLen/50;
}
/**
* 获取修正后的Y刻度对应的文本的显示横向偏移量
*/
private getYTextBias(value:string){
let bias = value.length
if(bias == 1){
return 1
}
return bias * 3.5;
}
}
export let B4Q2D:BoardInfo = new board4Q2D()
export let B1Q2D:BoardInfo = new board1Q2D()

View File

@ -1,31 +0,0 @@
/*
Copyright 2026 LI Meng
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export enum PointType{
DISCONTINUE = 0,
CONTINUE = 1
}
/**
* 虚拟点集
* 根据函数关系和步长、个数直接得到的点集
*/
export interface IPoint{
x:number
y:number
pointType:PointType
}

View File

@ -1,47 +0,0 @@
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.FILE_ACCESS_MANAGER"
},
{
"name": "ohos.permission.GET_BUNDLE_INFO_PRIVILEGED"
}
],
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"default",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"orientation": "landscape",
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
]
}
}

View File

@ -1,8 +0,0 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -1,16 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -1,5 +0,0 @@
{
"src": [
"pages/Index"
]
}

View File

@ -1,16 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
}
]
}

View File

@ -1,16 +0,0 @@
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
}
]
}

View File

@ -1,35 +0,0 @@
import hilog from '@ohos.hilog';
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
export default function abilityTest() {
describe('ActsAbilityTest', () => {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(() => {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
})
beforeEach(() => {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
})
afterEach(() => {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
})
afterAll(() => {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
})
it('assertContain', 0, () => {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
let a = 'abc';
let b = 'b';
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b);
expect(a).assertEqual(a);
})
})
}

View File

@ -1,5 +0,0 @@
import abilityTest from './Ability.test';
export default function testsuite() {
abilityTest();
}

View File

@ -1,50 +0,0 @@
import UIAbility from '@ohos.app.ability.UIAbility';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import hilog from '@ohos.hilog';
import { Hypium } from '@ohos/hypium';
import testsuite from '../test/List.test';
import window from '@ohos.window';
import Want from '@ohos.app.ability.Want';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
export default class TestAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator;
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs;
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments();
hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
windowStage.loadContent('testability/pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
}
onForeground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
}
onBackground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
}
}

View File

@ -1,17 +0,0 @@
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
}
.width('100%')
}
.height('100%')
}
}

View File

@ -1,47 +0,0 @@
import hilog from '@ohos.hilog';
import TestRunner from '@ohos.application.testRunner';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import Want from '@ohos.app.ability.Want';
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator | undefined = undefined
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs | undefined = undefined
async function onAbilityCreateCallback() {
hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
}
async function addAbilityMonitorCallback(err : Error) {
hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
}
export default class OpenHarmonyTestRunner implements TestRunner {
constructor() {
}
onPrepare() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
}
async onRun() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
const bundleName = abilityDelegatorArguments.bundleName;
const testAbilityName = 'TestAbility';
let lMonitor: AbilityDelegatorRegistry.AbilityMonitor = {
abilityName: testAbilityName,
onAbilityCreate: onAbilityCreateCallback,
};
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
const want: Want = {
bundleName: bundleName,
abilityName: testAbilityName
};
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
abilityDelegator.startAbility(want, (err, data) => {
hilog.info(0x0000, 'testTag', 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
hilog.info(0x0000, 'testTag', 'startAbility : data : %{public}s',JSON.stringify(data) ?? '');
})
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
}
}

View File

@ -1,37 +0,0 @@
{
"module": {
"name": "entry_test",
"type": "feature",
"description": "$string:module_test_desc",
"mainElement": "TestAbility",
"deviceTypes": [
"default",
"tablet"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:test_pages",
"abilities": [
{
"name": "TestAbility",
"srcEntry": "./ets/testability/TestAbility.ets",
"description": "$string:TestAbility_desc",
"icon": "$media:icon",
"label": "$string:TestAbility_label",
"exported": true,
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"skills": [
{
"actions": [
"action.system.home"
],
"entities": [
"entity.system.home"
]
}
]
}
]
}
}

View File

@ -1,8 +0,0 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -1,16 +0,0 @@
{
"string": [
{
"name": "module_test_desc",
"value": "test ability description"
},
{
"name": "TestAbility_desc",
"value": "the test ability"
},
{
"name": "TestAbility_label",
"value": "test label"
}
]
}

Some files were not shown because too many files have changed in this diff Show More