Эх сурвалжийг харах

博士安全 鸿蒙版提交

bjb 1 долоо хоног өмнө
commit
a83ccb469b
73 өөрчлөгдсөн 1565 нэмэгдсэн , 0 устгасан
  1. 12 0
      .gitignore
  2. 10 0
      AppScope/app.json5
  3. 8 0
      AppScope/resources/base/element/string.json
  4. BIN
      AppScope/resources/base/media/background.png
  5. BIN
      AppScope/resources/base/media/foreground.png
  6. 7 0
      AppScope/resources/base/media/layered_image.json
  7. 8 0
      AppScope/resources/zh_CN/element/strings.json
  8. 56 0
      build-profile.json5
  9. 32 0
      code-linter.json5
  10. 6 0
      entry/.gitignore
  11. 33 0
      entry/build-profile.json5
  12. 6 0
      entry/hvigorfile.ts
  13. 23 0
      entry/obfuscation-rules.txt
  14. 10 0
      entry/oh-package.json5
  15. 17 0
      entry/src/main/ets/api/req/ReqApi.ets
  16. 11 0
      entry/src/main/ets/api/req/ReqLogin.ets
  17. 6 0
      entry/src/main/ets/api/rsp/Rsp.ets
  18. 8 0
      entry/src/main/ets/api/rsp/RspLogin.ets
  19. 56 0
      entry/src/main/ets/components/loading/Loading.ets
  20. 45 0
      entry/src/main/ets/components/loading/LoadingView.ets
  21. 61 0
      entry/src/main/ets/entry/Entry.ets
  22. 16 0
      entry/src/main/ets/entry/EntryBackup.ets
  23. 71 0
      entry/src/main/ets/pages/PageHome.ets
  24. 260 0
      entry/src/main/ets/pages/PageHomeComponents/TabHome.ets
  25. 6 0
      entry/src/main/ets/pages/PageHomeComponents/TabJobs.ets
  26. 6 0
      entry/src/main/ets/pages/PageHomeComponents/TabMessage.ets
  27. 6 0
      entry/src/main/ets/pages/PageHomeComponents/TabSettings.ets
  28. 164 0
      entry/src/main/ets/pages/PageLogin.ets
  29. 31 0
      entry/src/main/ets/pages/PageSplash.ets
  30. 131 0
      entry/src/main/ets/utils/HttpClient.ets
  31. 74 0
      entry/src/main/ets/utils/Storage.ets
  32. 16 0
      entry/src/main/ets/utils/SysUtils.ets
  33. 12 0
      entry/src/main/ets/vm/VMHome.ets
  34. 24 0
      entry/src/main/ets/vm/VMHomeTab.ets
  35. 53 0
      entry/src/main/ets/vm/VMLogin.ets
  36. 55 0
      entry/src/main/module.json5
  37. 8 0
      entry/src/main/resources/base/element/color.json
  38. 8 0
      entry/src/main/resources/base/element/float.json
  39. 8 0
      entry/src/main/resources/base/element/string.json
  40. BIN
      entry/src/main/resources/base/media/background.png
  41. 1 0
      entry/src/main/resources/base/media/bell.svg
  42. 0 0
      entry/src/main/resources/base/media/bluetooth.svg
  43. 1 0
      entry/src/main/resources/base/media/code.svg
  44. 0 0
      entry/src/main/resources/base/media/fingerprint.svg
  45. BIN
      entry/src/main/resources/base/media/foreground.png
  46. 1 0
      entry/src/main/resources/base/media/home.svg
  47. 1 0
      entry/src/main/resources/base/media/job_finish.svg
  48. 1 0
      entry/src/main/resources/base/media/job_ing.svg
  49. 1 0
      entry/src/main/resources/base/media/job_todo.svg
  50. 1 0
      entry/src/main/resources/base/media/jobs.svg
  51. 7 0
      entry/src/main/resources/base/media/layered_image.json
  52. 1 0
      entry/src/main/resources/base/media/location.svg
  53. 1 0
      entry/src/main/resources/base/media/message.svg
  54. 7 0
      entry/src/main/resources/base/media/phone.svg
  55. 1 0
      entry/src/main/resources/base/media/pwd.svg
  56. 0 0
      entry/src/main/resources/base/media/qrcode.svg
  57. 0 0
      entry/src/main/resources/base/media/settings.svg
  58. BIN
      entry/src/main/resources/base/media/startIcon.png
  59. 0 0
      entry/src/main/resources/base/media/tips.svg
  60. 1 0
      entry/src/main/resources/base/media/user.svg
  61. 3 0
      entry/src/main/resources/base/profile/backup_config.json
  62. 7 0
      entry/src/main/resources/base/profile/main_pages.json
  63. 8 0
      entry/src/main/resources/dark/element/color.json
  64. 2 0
      entry/src/mock/mock-config.json5
  65. 35 0
      entry/src/ohosTest/ets/test/Ability.test.ets
  66. 5 0
      entry/src/ohosTest/ets/test/List.test.ets
  67. 11 0
      entry/src/ohosTest/module.json5
  68. 5 0
      entry/src/test/List.test.ets
  69. 33 0
      entry/src/test/LocalUnit.test.ets
  70. 23 0
      hvigor/hvigor-config.json5
  71. 6 0
      hvigorfile.ts
  72. 28 0
      oh-package-lock.json5
  73. 10 0
      oh-package.json5

+ 12 - 0
.gitignore

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

+ 10 - 0
AppScope/app.json5

@@ -0,0 +1,10 @@
+{
+  "app": {
+    "bundleName": "com.iscs.bozzys",
+    "vendor": "bozzys",
+    "versionCode": 1000000,
+    "versionName": "1.0.0",
+    "icon": "$media:layered_image",
+    "label": "$string:app_name"
+  }
+}

+ 8 - 0
AppScope/resources/base/element/string.json

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

BIN
AppScope/resources/base/media/background.png


BIN
AppScope/resources/base/media/foreground.png


+ 7 - 0
AppScope/resources/base/media/layered_image.json

@@ -0,0 +1,7 @@
+{
+  "layered-image":
+  {
+    "background" : "$media:background",
+    "foreground" : "$media:foreground"
+  }
+}

+ 8 - 0
AppScope/resources/zh_CN/element/strings.json

@@ -0,0 +1,8 @@
+{
+  "string": [
+    {
+      "name": "app_name",
+      "value": "博士安全"
+    }
+  ]
+}

+ 56 - 0
build-profile.json5

@@ -0,0 +1,56 @@
+{
+  "app": {
+    "signingConfigs": [
+      {
+        "name": "default",
+        "type": "HarmonyOS",
+        "material": {
+          "certpath": "C:\\Users\\ISCS\\.ohos\\config\\default_Bozzys_HMOS_IJZctqqYeqIPOdk4yyWMI1byWLyPOaDXRx-iocotmiI=.cer",
+          "keyAlias": "debugKey",
+          "keyPassword": "0000001B8083B87E72425B072D91488198CFB0D70F22F2AEBEA5F57D6D97B6CB471C0180E5A0E7CF983AA5",
+          "profile": "C:\\Users\\ISCS\\.ohos\\config\\default_Bozzys_HMOS_IJZctqqYeqIPOdk4yyWMI1byWLyPOaDXRx-iocotmiI=.p7b",
+          "signAlg": "SHA256withECDSA",
+          "storeFile": "C:\\Users\\ISCS\\.ohos\\config\\default_Bozzys_HMOS_IJZctqqYeqIPOdk4yyWMI1byWLyPOaDXRx-iocotmiI=.p12",
+          "storePassword": "0000001B8DA6312148966308E49E360C499133CBAF5079D736B4F7B945F2D367F85CC3C7564114A11F7FF4"
+        }
+      }
+    ],
+    "products": [
+      {
+        "name": "default",
+        "signingConfig": "default",
+        "targetSdkVersion": "6.0.1(21)",
+        "compatibleSdkVersion": "6.0.1(21)",
+        "runtimeOS": "HarmonyOS",
+        "buildOption": {
+          "strictMode": {
+            "caseSensitiveCheck": true,
+            "useNormalizedOHMUrl": true
+          }
+        }
+      }
+    ],
+    "buildModeSet": [
+      {
+        "name": "debug",
+      },
+      {
+        "name": "release"
+      }
+    ]
+  },
+  "modules": [
+    {
+      "name": "entry",
+      "srcPath": "./entry",
+      "targets": [
+        {
+          "name": "default",
+          "applyToProducts": [
+            "default"
+          ]
+        }
+      ]
+    }
+  ]
+}

+ 32 - 0
code-linter.json5

@@ -0,0 +1,32 @@
+{
+  "files": [
+    "**/*.ets"
+  ],
+  "ignore": [
+    "**/src/ohosTest/**/*",
+    "**/src/test/**/*",
+    "**/src/mock/**/*",
+    "**/node_modules/**/*",
+    "**/oh_modules/**/*",
+    "**/build/**/*",
+    "**/.preview/**/*"
+  ],
+  "ruleSet": [
+    "plugin:@performance/recommended",
+    "plugin:@typescript-eslint/recommended"
+  ],
+  "rules": {
+    "@security/no-unsafe-aes": "error",
+    "@security/no-unsafe-hash": "error",
+    "@security/no-unsafe-mac": "warn",
+    "@security/no-unsafe-dh": "error",
+    "@security/no-unsafe-dsa": "error",
+    "@security/no-unsafe-ecdsa": "error",
+    "@security/no-unsafe-rsa-encrypt": "error",
+    "@security/no-unsafe-rsa-sign": "error",
+    "@security/no-unsafe-rsa-key": "error",
+    "@security/no-unsafe-dsa-key": "error",
+    "@security/no-unsafe-dh-key": "error",
+    "@security/no-unsafe-3des": "error"
+  }
+}

+ 6 - 0
entry/.gitignore

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

+ 33 - 0
entry/build-profile.json5

@@ -0,0 +1,33 @@
+{
+  "apiType": "stageMode",
+  "buildOption": {
+    "resOptions": {
+      "copyCodeResource": {
+        "enable": false
+      }
+    }
+  },
+  "buildOptionSet": [
+    {
+      "name": "release",
+      "arkOptions": {
+        "obfuscation": {
+          "ruleOptions": {
+            "enable": false,
+            "files": [
+              "./obfuscation-rules.txt"
+            ]
+          }
+        }
+      }
+    },
+  ],
+  "targets": [
+    {
+      "name": "default"
+    },
+    {
+      "name": "ohosTest",
+    }
+  ]
+}

+ 6 - 0
entry/hvigorfile.ts

@@ -0,0 +1,6 @@
+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. */
+}

+ 23 - 0
entry/obfuscation-rules.txt

@@ -0,0 +1,23 @@
+# 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://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
+
+# 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
+
+-enable-property-obfuscation
+-enable-toplevel-obfuscation
+-enable-filename-obfuscation
+-enable-export-obfuscation

+ 10 - 0
entry/oh-package.json5

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

+ 17 - 0
entry/src/main/ets/api/req/ReqApi.ets

@@ -0,0 +1,17 @@
+import { Request } from '../../utils/HttpClient';
+import { RspLogin } from '../rsp/RspLogin';
+import { ReqLogin } from './ReqLogin';
+
+export class ReqApi {
+  /**
+   * 登录接口
+   *
+   * @param username  用户名
+   * @param pwd       密码
+   * @returns
+   */
+  static login(username: string, pwd: string): Promise<RspLogin> {
+    const req = new ReqLogin(username, pwd)
+    return Request.post("/login", req)
+  }
+}

+ 11 - 0
entry/src/main/ets/api/req/ReqLogin.ets

@@ -0,0 +1,11 @@
+export class ReqLogin {
+  // 用户名
+  username: string = ""
+  // 密码
+  password: string = ""
+
+  constructor(username: string, pwd: string) {
+    this.username = username
+    this.password = pwd
+  }
+}

+ 6 - 0
entry/src/main/ets/api/rsp/Rsp.ets

@@ -0,0 +1,6 @@
+export class Rsp {
+  // 响应码
+  code: number = 0
+  // 响应信息
+  msg: string = ""
+}

+ 8 - 0
entry/src/main/ets/api/rsp/RspLogin.ets

@@ -0,0 +1,8 @@
+import { Rsp } from './Rsp';
+
+export class RspLogin extends Rsp {
+  // 用户昵称
+  nickName: string = ""
+  // 用户Token
+  token: string = ""
+}

+ 56 - 0
entry/src/main/ets/components/loading/Loading.ets

@@ -0,0 +1,56 @@
+import { LoadingView } from './LoadingView'
+import { ComponentContent, PromptAction } from '@kit.ArkUI'
+
+export class Loading {
+  static uiContext?: UIContext
+  static promptAction?: PromptAction
+  static componentContent?: ComponentContent<LoadingBuilderOptions>
+
+  static init(uiContext: UIContext) {
+    if (!Loading.uiContext) {
+      Loading.uiContext = uiContext
+      Loading.promptAction = Loading.uiContext.getPromptAction();
+      Loading.componentContent = new ComponentContent(Loading.uiContext, wrapBuilder(loadingBuilder));
+    }
+  }
+
+  static async showLoading(options: LoadingBuilderOptions | string = {}) {
+    if (Loading.uiContext) {
+      let loadingProps = options
+      if (typeof options === 'string') {
+        loadingProps = { text: options }
+      }
+      const opt = loadingProps as LoadingBuilderOptions
+      Loading.componentContent?.update(opt)
+
+      try {
+        await Loading.promptAction?.openCustomDialog(Loading.componentContent, {
+          autoCancel: opt.autoCancel == true,
+          transition: TransitionEffect.IDENTITY,
+          maskColor: Color.Transparent
+        })
+      } catch (error) {
+        // Dialog显示异常
+      }
+    }
+  }
+
+  static async hideLoading() {
+    Loading.promptAction?.closeCustomDialog(Loading.componentContent).catch(() => {
+      // Dialog隐藏异常
+    })
+  }
+}
+
+@Builder
+function loadingBuilder(options: LoadingBuilderOptions = {}) {
+  LoadingView({
+    loadingTips: options?.text || '加载中...'
+  })
+}
+
+
+export interface LoadingBuilderOptions {
+  text?: string,
+  autoCancel?: boolean
+}

+ 45 - 0
entry/src/main/ets/components/loading/LoadingView.ets

@@ -0,0 +1,45 @@
+@CustomDialog
+@Component
+export struct LoadingView {
+  controller: CustomDialogController;
+  @Prop loadingTips: string = '加载中...'
+  @Prop loadingImage: ResourceStr = $r('app.media.tips')
+  @Prop imageRotate: RotateOptions = { angle: 0 }
+
+  build() {
+    Column() {
+      Row() {
+        LoadingProgress().width(44).height(44).color(Color.White)
+        // Image(this.loadingImage)
+        //   .height(44)
+        //   .width(44)
+        //   .rotate(this.imageRotate)
+        //   .onComplete(() => {
+        //     this.imageRotate = { angle: 360 }
+        //   })
+        //   .animation({
+        //     duration: 1000,
+        //     curve: Curve.Linear,
+        //     delay: 0,
+        //     iterations: -1, // 无限次
+        //     playMode: PlayMode.Normal
+        //   })
+      }
+
+      Text(this.loadingTips)
+        .fontColor(Color.White)
+        .fontSize(16)
+        .margin({
+          top: 10
+        })
+    }
+    .constraintSize({
+      minWidth: 104,
+      maxWidth: 104,
+      minHeight: 104
+    })
+    .padding(16)
+    .borderRadius(8)
+    .backgroundColor('rgba(0, 0, 0, 0.7)')
+  }
+}

+ 61 - 0
entry/src/main/ets/entry/Entry.ets

@@ -0,0 +1,61 @@
+import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { window } from '@kit.ArkUI';
+import { Storage } from '../utils/Storage';
+import { Loading } from '../components/loading/Loading';
+
+const DOMAIN = 0x0000;
+
+export default class EntryAbility extends UIAbility {
+  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
+    try {
+      this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
+    } catch (err) {
+      hilog.error(DOMAIN, 'testTag', 'Failed to set colorMode. Cause: %{public}s', JSON.stringify(err));
+    }
+    // 初始化存储工具
+    Storage.init(this.context)
+    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
+  }
+
+  onDestroy(): void {
+    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy');
+  }
+
+  onWindowStageCreate(windowStage: window.WindowStage): void {
+    // 设置沉浸式状态栏
+    // try {
+    //   const window = windowStage.getMainWindowSync()
+    //   window.setWindowLayoutFullScreen(true).catch(() => {})
+    // } catch (error) {
+    //
+    // }
+    // Main window is created, set main page for this ability
+    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
+    windowStage.loadContent('pages/PageSplash', (err) => {
+      if (err.code) {
+        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
+        return;
+      }
+      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
+      // 加载Loading弹窗
+      const ctx = windowStage.getMainWindowSync().getUIContext()
+      Loading.init(ctx)
+    });
+  }
+
+  onWindowStageDestroy(): void {
+    // Main window is destroyed, release UI related resources
+    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
+  }
+
+  onForeground(): void {
+    // Ability has brought to foreground
+    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
+  }
+
+  onBackground(): void {
+    // Ability has back to background
+    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
+  }
+}

+ 16 - 0
entry/src/main/ets/entry/EntryBackup.ets

@@ -0,0 +1,16 @@
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit';
+
+const DOMAIN = 0x0000;
+
+export default class EntryBackupAbility extends BackupExtensionAbility {
+  async onBackup() {
+    hilog.info(DOMAIN, 'testTag', 'onBackup ok');
+    await Promise.resolve();
+  }
+
+  async onRestore(bundleVersion: BundleVersion) {
+    hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion));
+    await Promise.resolve();
+  }
+}

+ 71 - 0
entry/src/main/ets/pages/PageHome.ets

@@ -0,0 +1,71 @@
+import { VMHome } from '../vm/VMHome'
+import { TabHome } from './PageHomeComponents/TabHome'
+import { TabJobs } from './PageHomeComponents/TabJobs'
+import { TabMessage } from './PageHomeComponents/TabMessage'
+import { TabSettings } from './PageHomeComponents/TabSettings'
+
+@Entry
+@Component
+struct PageHome {
+  @State vm: VMHome = new VMHome()
+
+  build() {
+    Tabs({ barPosition: BarPosition.End, index: this.vm.tabIndex }) {
+      TabContent() {
+        TabHome({ vmHome: this.vm })
+      }
+      .tabBar(this.TabBuilder(0, "首页", $r('app.media.home')))
+      .clip(false)
+
+      TabContent() {
+        TabJobs()
+      }
+      .tabBar(this.TabBuilder(1, "作业", $r('app.media.jobs')))
+
+      TabContent() {
+        TabMessage()
+      }
+      .tabBar(this.TabBuilder(2, "消息", $r('app.media.message')))
+
+      TabContent() {
+        TabSettings()
+      }
+      .tabBar(this.TabBuilder(3, "设置", $r("app.media.settings")))
+    }
+    .width('100%')
+    .height('100%')
+    .barMode(BarMode.Fixed)
+    .divider({ color: "#EEEEEE", strokeWidth: 1 })
+    .scrollable(false)
+    .animationMode(AnimationMode.NO_ANIMATION)
+    .onChange((index: number) => {
+      // 该方法实现双向绑定,以处理非用户点击导致的导航栏变化
+      this.vm.updateTabIndex(index)
+    })
+    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
+
+  }
+
+  @Builder
+  TabBuilder(id: number, text: string, icon: Resource) {
+    Stack() {
+      Column() {
+        Image(icon).width(20).height(20).fillColor(id == this.vm.tabIndex ? "#1E90FF" : "#333333")
+        Text(text)
+          .fontSize(12)
+          .fontColor(id == this.vm.tabIndex ? "#1E90FF" : "#333333")
+          .margin({ top: 5 })
+      }.width("100%").height("100%").justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
+
+      Text("99")
+        .backgroundColor("#FF4500")
+        .borderRadius("50%")
+        .fontColor(Color.White)
+        .fontSize(10)
+        .position({ top: 2, left: "55%" })
+        .constraintSize({ minWidth: 15, minHeight: 15 })
+        .textAlign(TextAlign.Center)
+        .visibility(Visibility.Hidden)
+    }.width("100%").height(56)
+  }
+}

+ 260 - 0
entry/src/main/ets/pages/PageHomeComponents/TabHome.ets

@@ -0,0 +1,260 @@
+import { VMHome } from '../../vm/VMHome'
+import { VMHomeTab } from '../../vm/VMHomeTab'
+
+/**
+ * 首页Tab页面
+ */
+@Component
+export struct TabHome {
+  // 父组件传递
+  @Link vmHome: VMHome
+  // 页面状态
+  @State vm: VMHomeTab = new VMHomeTab()
+
+  aboutToAppear(): void {
+    this.vm.init()
+  }
+
+  build() {
+    Column() {
+      this.TopBar()
+      Refresh({ refreshing: $$this.vm.isRefreshing }) {
+        Column() {
+          this.TODOStatus()
+          this.TODOList()
+        }.width("100%").height("100%")
+      }.width("100%").layoutWeight(1).onRefreshing(() => {
+        this.vm.onRefresh()
+      })
+    }
+    .width("100%")
+    .height("100%")
+    .clip(false)
+    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
+  }
+
+  /**
+   * 顶部状态栏
+   */
+  @Builder
+  TopBar() {
+    Column() {
+      Row() {
+        Image($r("app.media.user"))
+          .width(36)
+          .height(36)
+          .borderRadius("50%")
+          .backgroundColor("#FFD700")
+          .padding(8)
+          .fillColor(Color.White)
+        Column() {
+          Text(this.vm.username).fontSize(16).fontColor(Color.White).fontWeight(FontWeight.Medium)
+          Text("操作员 电气维护组").fontSize(12).fontColor(Color.White).opacity(0.8)
+        }.layoutWeight(1).margin({ left: 10, right: 10 }).alignItems(HorizontalAlign.Start)
+
+        Stack() {
+          Image($r("app.media.bell")).width(19).height(19).fillColor(Color.White)
+          Text("99")
+            .backgroundColor("#FF4500")
+            .borderRadius("50%")
+            .fontColor(Color.White)
+            .fontSize(10)
+            .position({ top: -5, left: "52%" })
+            .constraintSize({ minWidth: 15, minHeight: 15 })
+            .textAlign(TextAlign.Center)
+        }.width(36).height(24).onClick(() => {
+        })
+
+        Stack() {
+          Image($r("app.media.settings")).width(18).height(18).fillColor(Color.White)
+        }.width(36).height(24).onClick(() => {
+        })
+      }
+      .width("100%")
+      .padding({
+        left: 16,
+        top: 15,
+        right: 16,
+        bottom: 15
+      })
+    }
+    .width("100%")
+    .backgroundColor("#FFA500")
+    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
+  }
+
+  /**
+   * 待办状态
+   */
+  @Builder
+  TODOStatus() {
+    Column() {
+      Text("中午好,今天有2个待办任务")
+        .width("100%")
+        .height(51)
+        .backgroundColor("#E6F7FF")
+        .fontSize(14)
+        .fontColor("#333333")
+        .textAlign(TextAlign.Center)
+      Row() {
+        Column() {
+          Text("2").fontSize(24).fontColor("#FF4500").fontWeight(FontWeight.Bold)
+          Text("待处理").fontSize(12).fontColor("#333333").margin({ top: 10, bottom: 5 })
+          Image($r("app.media.job_todo")).width(18).height(18).fillColor(Color.Black)
+        }
+        .margin(5)
+        .layoutWeight(1)
+        .aspectRatio(1)
+        .backgroundColor("#FFF5EB")
+        .borderRadius(12)
+        .justifyContent(FlexAlign.Center)
+
+        Column() {
+          Text("5").fontSize(24).fontColor("#FFA500").fontWeight(FontWeight.Bold)
+          Text("进行中").fontSize(12).fontColor("#333333").margin({ top: 10, bottom: 5 })
+          Image($r("app.media.job_ing")).width(18).height(18).fillColor(Color.Black)
+        }
+        .margin(5)
+        .layoutWeight(1)
+        .aspectRatio(1)
+        .backgroundColor("#FFF5EB")
+        .borderRadius(12)
+        .justifyContent(FlexAlign.Center)
+
+        Column() {
+          Text("10").fontSize(24).fontColor("#32CD32").fontWeight(FontWeight.Bold)
+          Text("本月完成").fontSize(12).fontColor("#333333").margin({ top: 10, bottom: 5 })
+          Image($r("app.media.job_finish")).width(18).height(18).fillColor(Color.Black)
+        }
+        .margin(5)
+        .layoutWeight(1)
+        .aspectRatio(1)
+        .backgroundColor("#FFF5EB")
+        .borderRadius(12)
+        .justifyContent(FlexAlign.Center)
+      }
+      .padding({
+        left: 5,
+        right: 5,
+        top: 10,
+        bottom: 10
+      })
+    }.width("100%").margin({ top: 3 })
+  }
+
+  @Builder
+  TODOList() {
+    List() {
+      ListItem() {
+        Row() {
+          Text("我的当前任务").fontSize(14).fontColor("#333333").fontWeight(FontWeight.Medium)
+          Row().layoutWeight(1)
+          Text("查看全部").fontSize(14).fontColor("#1E90FF").fontWeight(FontWeight.Medium)
+        }.width("100%").height(46).onClick(() => {
+          this.vmHome.updateTabIndex(1)
+        })
+      }
+
+      ForEach([1, 2], (item: number, index: number) => {
+        ListItem() {
+          Column() {
+            Row() {
+              Text("冷却水系统能量隔离作业").fontSize(15).fontColor("#333333").fontWeight(FontWeight.Medium)
+              Row().layoutWeight(1)
+              Text("待办")
+                .fontSize(12)
+                .fontColor("#333333")
+                .backgroundColor("#FFD700")
+                .borderRadius(20)
+                .height(24)
+                .padding({ left: 10, right: 10 })
+                .textAlign(TextAlign.Center)
+            }
+
+            Flex({ wrap: FlexWrap.Wrap, alignItems: ItemAlign.Center, direction: FlexDirection.Row }) {
+              Image($r("app.media.location")).width(12).height(12).fillColor("#1E90FF").margin({ right: 5 })
+              Text("车间B区")
+                .fontSize(13)
+                .fontColor("#666666")
+                .margin({ right: 12 })
+                .height(24)
+                .textAlign(TextAlign.Center)
+              Image($r("app.media.user")).width(12).height(12).fillColor("#666666").margin({ right: 5 })
+              Text("负责人:王主管哈哈哈哈")
+                .fontSize(13)
+                .fontColor("#666666")
+                .margin({ right: 12 })
+                .height(24)
+                .textAlign(TextAlign.Center)
+              Image($r("app.media.jobs")).width(12).height(12).fillColor("#666666").margin({ right: 5 })
+              Text("WO-2025-005")
+                .fontSize(13)
+                .fontColor("#666666")
+                .margin({ right: 12 })
+                .height(24)
+                .textAlign(TextAlign.Center)
+            }.margin({ top: 10 })
+
+            Text("作业内容:上锁挂牌").fontSize(13).fontColor("#666666").height(24).textAlign(TextAlign.Center)
+
+            Row() {
+              Text("今天 14:00").layoutWeight(1).margin({ right: 10 }).fontColor("#999999").fontSize(12)
+              Button("查看详情")
+                .height(35)
+                .padding({ left: 15, right: 15 })
+                .backgroundColor("#4682B4")
+                .borderRadius(4)
+                .fontSize(13)
+                .fontWeight(FontWeight.Medium)
+            }.width("100%").layoutWeight(1)
+          }.width("100%").height("100%").justifyContent(FlexAlign.Start).alignItems(HorizontalAlign.Start)
+        }
+        .width("100%")
+        .height(175)
+        .backgroundColor("#F8F9FA")
+        .borderRadius(12)
+        .border({ width: 1, color: "#EEEEEE" })
+        .margin({ bottom: index == 1 ? 0 : 15 })
+        .padding(16)
+      })
+      ListItem() {
+        Row() {
+          Text("最新消息").fontSize(14).fontColor("#333333").fontWeight(FontWeight.Medium)
+          Row().layoutWeight(1)
+          Text("全部消息").fontSize(14).fontColor("#1E90FF").fontWeight(FontWeight.Medium)
+        }.width("100%").height(46).onClick(() => {
+          this.vmHome.updateTabIndex(2)
+        })
+      }
+
+      ForEach([1, 2], (item: number) => {
+        ListItem() {
+          Column() {
+            Text("系统通知:您有新的作业任务待处理,请及时查看并执行操作,请及时查看并执行操作,请及时查看并执行操作,请及时查看并执行操作")
+              .fontSize(14)
+              .fontColor("#333333")
+              .textOverflow({ overflow: TextOverflow.Ellipsis }).maxLines(2)
+            Text("5分钟前")
+              .layoutWeight(1)
+              .width("100%")
+              .textAlign(TextAlign.End)
+              .fontSize(12)
+              .fontColor("#999999")
+          }
+          .width("100%")
+          .height("100%")
+          .justifyContent(FlexAlign.Start)
+          .alignItems(HorizontalAlign.Start)
+          .padding(16)
+        }
+        .width("100%")
+        .height(102)
+        .backgroundColor("#F8F9FA")
+        .borderRadius(12)
+        .border({ width: 1, color: "#EEEEEE" })
+        .margin({ bottom: 15 })
+      })
+    }
+    .width("100%").layoutWeight(1).padding({ left: 20, right: 20 }).scrollBar(BarState.Off)
+  }
+}

+ 6 - 0
entry/src/main/ets/pages/PageHomeComponents/TabJobs.ets

@@ -0,0 +1,6 @@
+@Component
+export struct TabJobs {
+  build() {
+    Text("我是作业")
+  }
+}

+ 6 - 0
entry/src/main/ets/pages/PageHomeComponents/TabMessage.ets

@@ -0,0 +1,6 @@
+@Component
+export struct TabMessage {
+  build() {
+    Text("我是消息")
+  }
+}

+ 6 - 0
entry/src/main/ets/pages/PageHomeComponents/TabSettings.ets

@@ -0,0 +1,6 @@
+@Component
+export struct TabSettings {
+  build() {
+    Text("我是设置")
+  }
+}

+ 164 - 0
entry/src/main/ets/pages/PageLogin.ets

@@ -0,0 +1,164 @@
+import { VMLogin } from '../vm/VMLogin'
+import { hideKeyboard } from '../utils/SysUtils'
+
+/**
+ * 登录页面
+ */
+@Entry
+@Component
+struct PageLogin {
+  // 登录页面状态管理
+  @State vm: VMLogin = new VMLogin()
+
+  build() {
+    Column() {
+      Column() {
+        Text("博士安全能量隔离系统").fontSize(24).fontColor("#333333").margin({ top: 60 })
+        Text("温州博士安全科技有限公司").fontSize(14).fontColor("#4B5563").margin({ top: 8, bottom: 30 })
+      }
+      .width("100%").backgroundColor($r("app.color.main")).expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])
+
+      Scroll() {
+        Column() {
+          Text("欢迎登录").fontSize(20).fontColor("#333333").fontWeight(FontWeight.Bold).margin({ top: 30 })
+          // 切换短信登录或者密码登录
+          Row() {
+            Text("短信登录")
+              .layoutWeight(1)
+              .height("100%")
+              .textAlign(TextAlign.Center)
+              .fontSize(14)
+              .fontColor(this.vm.loginType == 0 ? "#FFA500" : "#4B5563")
+              .backgroundColor(this.vm.loginType == 0 ? "#FFEDD5" : "#FFFFFF")
+              .onClick(() => {
+                this.vm.setLoginType(0)
+              })
+            Text("密码登录")
+              .layoutWeight(1)
+              .height("100%")
+              .textAlign(TextAlign.Center)
+              .fontSize(14)
+              .fontColor(this.vm.loginType == 1 ? "#FFA500" : "#4B5563")
+              .backgroundColor(this.vm.loginType == 1 ? "#FFEDD5" : "#FFFFFF")
+              .onClick(() => {
+                this.vm.setLoginType(1)
+              })
+          }.width(335).height(47).border({ width: 1, color: "#D1D5DB", radius: 8 }).margin({ top: 25 })
+
+          // 手机号或账号输入框
+          Row() {
+            Image(this.vm.loginType == 0 ? $r("app.media.phone") : $r("app.media.user"))
+              .width(18)
+              .height(18)
+              .fillColor("#999999")
+            TextInput({ placeholder: this.vm.loginType == 0 ? "请输入手机号" : "请输入用户名" })
+              .placeholderColor("#9CA3AF")
+              .fontSize(16)
+              .backgroundColor(Color.Transparent)
+              .type(this.vm.loginType == 0 ? InputType.PhoneNumber : InputType.Email)
+              .onChange((value) => {
+                this.vm.updateAccount(value)
+              })
+          }
+          .width(335)
+          .height(50)
+          .border({ width: 1, color: "#D1D5DB", radius: 4 })
+          .margin({ top: 25 })
+          .padding({ left: 12, right: 12 })
+
+          // 密码或验证码
+          Row() {
+            Image(this.vm.loginType == 0 ? $r("app.media.code") : $r("app.media.pwd"))
+              .width(18)
+              .height(18)
+              .fillColor("#999999")
+            TextInput({ placeholder: this.vm.loginType == 0 ? "请输入验证码" : "请输入密码" })
+              .placeholderColor("#9CA3AF")
+              .fontSize(16)
+              .backgroundColor(Color.Transparent)
+              .type(this.vm.loginType == 0 ? InputType.PhoneNumber : InputType.Password)
+              .showPasswordIcon(false)
+              .onChange((value) => {
+                this.vm.updateCode(value)
+              })
+          }
+          .width(335)
+          .height(50)
+          .border({ width: 1, color: "#D1D5DB", radius: 4 })
+          .margin({ top: 20 })
+          .padding({ left: 12, right: 12 })
+
+          // 登录按钮
+          Button("登 录")
+            .width(335)
+            .height(52)
+            .backgroundColor("#FFA500")
+            .margin({ top: 30 })
+            .border({ radius: 4 })
+            .onClick(() => {
+              this.vm.login(() => {
+                setTimeout(() => {
+                  this.getUIContext().getRouter().replaceUrl({ url: 'pages/PageHome' })
+                }, 1500)
+              })
+            })
+
+          Flex({ wrap: FlexWrap.Wrap, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
+            Image($r("app.media.tips")).fillColor("#6B7280").width(12).height(12).margin({ right: 5 })
+            Text("工业安全系统,请妥善保管账号信息").fontSize(12).fontColor("#6B7280")
+          }.width(335).margin({ top: 16 })
+
+          Stack() {
+            Column().width(335).height(1).backgroundColor("#EEEEEE")
+            Text("其他登录方式")
+              .fontColor("#999999")
+              .fontSize(14)
+              .backgroundColor(Color.White)
+              .padding({ left: 6, right: 6 })
+
+          }.alignContent(Alignment.Center).margin({ top: 20 })
+
+          Row() {
+            Image($r("app.media.fingerprint"))
+              .width(50)
+              .height(50)
+              .padding(12)
+              .backgroundColor("#F5F5F5")
+              .borderRadius("50%")
+              .fillColor("#333333")
+              .margin({ left: 10, right: 10 })
+            Image($r("app.media.qrcode"))
+              .width(50)
+              .height(50)
+              .padding(12)
+              .backgroundColor("#F5F5F5")
+              .borderRadius("50%")
+              .fillColor("#333333")
+              .margin({ left: 10, right: 10 })
+            Image($r("app.media.bluetooth"))
+              .width(50)
+              .height(50)
+              .padding(14)
+              .backgroundColor("#F5F5F5")
+              .borderRadius("50%")
+              .fillColor("#333333")
+              .margin({ left: 10, right: 10 })
+          }
+          .width("100%")
+          .justifyContent(FlexAlign.Center)
+          .alignItems(VerticalAlign.Center)
+          .margin({ top: 30, bottom: 30 })
+
+          // 分割线
+          Column().width(335).height(1).backgroundColor("#EEEEEE")
+          Text("LOTO智能锁控·能量安全隔离").fontSize(14).fontColor("#666666").margin({ top: 20 })
+          Text("版本 v1.0.0").fontSize(14).fontColor("#666666").margin({ top: 5, bottom: 20 })
+        }
+        .width("100%").height("100%")
+      }.width("100%").height("100%")
+    }.onClick(() => {
+      console.log("隐藏键盘")
+      hideKeyboard()
+    })
+  }
+}

+ 31 - 0
entry/src/main/ets/pages/PageSplash.ets

@@ -0,0 +1,31 @@
+import { Storage } from '../utils/Storage'
+
+/**
+ * 闪屏页面
+ */
+@Entry
+@Component
+struct PageSplash {
+  build() {
+    RelativeContainer() {
+      Image($r("app.media.startIcon"))
+        .alignRules({
+          center: { anchor: '__container__', align: VerticalAlign.Center },
+          middle: { anchor: '__container__', align: HorizontalAlign.Center }
+        })
+        .width(320)
+    }
+    .height('100%')
+    .width('100%')
+  }
+
+  aboutToAppear(): void {
+    // 跳转到登录页面
+    const router = this.getUIContext().getRouter()
+    setTimeout(() => {
+      const url = Storage.isLogin() ? "pages/PageHome" : "pages/PageLogin"
+      router.replaceUrl({ url: url }).catch(() => {
+      })
+    }, 3000)
+  }
+}

+ 131 - 0
entry/src/main/ets/utils/HttpClient.ets

@@ -0,0 +1,131 @@
+import { http } from '@kit.NetworkKit'
+import { promptAction } from '@kit.ArkUI'
+import { Rsp } from '../api/rsp/Rsp'
+
+// 传输参数token
+export const TOKEN_KEY: string = 'token'
+
+//请求网络的基底址
+export const BASE_URL: string = 'http://120.27.232.27:9190'
+
+interface EmptyInterface {}
+
+
+//Next版本不支持在箭头函数上写纯泛型,
+// function requestHttp(url: url地址, method: 请求方法类型,默认为get, data?: 参数类型) : 返回类型是: Promise里面的T类型的数据
+async function requestHttp<T extends Rsp>(url: string = '', method: http.RequestMethod = http.RequestMethod.GET,
+  data?: object): Promise<T> {
+  // 创建一个网络请求
+  const httpRequest = http.createHttp()
+  // 拼接地址
+  let reqUrl = BASE_URL + url
+  // Get方法需要自己拼接
+  if (method == http.RequestMethod.GET) {
+    // 如果data里面有值并且里面有对象的时候
+    if (data && Object.keys(data).length) {
+      reqUrl += "?" + Object.keys(data).map(key => {
+        if (data[key]) {
+          return `${key}=${data[key]}` // a=1 =>
+        }
+        return ""
+      }).join('&') //['a=1','b=2','c=3']
+    }
+  }
+  //设置请求对象
+  let config: http.HttpRequestOptions = {
+    //method同名方法赋值,参数名和属性名相同时只需要写一个method等价于method:method
+    method,
+    //超时时间
+    readTimeout: 10000,
+    //get的extraData参数在上面处理过了 在这儿不需要再传一遍
+    extraData: method === http.RequestMethod.GET ? '' : data || {} as EmptyInterface,
+    //响应参数的类型,指定为对象后有BUG,当结果有问题时,项目会直接瘫痪
+    // expectDataType: http.HttpDataType.OBJECT,
+    //请求头
+    header: {
+      'Content-Type': 'application/json',
+      "Authorization": AppStorage.get(TOKEN_KEY) as string || ''
+    }
+  }
+  //发请求
+  try {
+    const res = await httpRequest.request(reqUrl, config)
+    console.log(method, '--->', reqUrl, JSON.stringify(config.extraData))
+    console.log(method, '<---', reqUrl, res.responseCode, res.result)
+    //res.responseCode响应状态码,这里的401还会认为是请求成功
+    if (res.responseCode === 401) {
+      // 401 token超时
+      // 删除持久化数据token
+      AppStorage.set<string>(TOKEN_KEY, '')
+      promptAction.openToast({ message: 'token timeout' })
+      // 回登录
+      // router.replaceUrl({ url: 'pages/Login/LoginPage' })
+      // 返回错误 终止
+      return Promise.reject(new Error('token timeout'))
+    } else if (res.responseCode === 404) {
+      promptAction.openToast({ message: 'not find' })
+      return Promise.reject(new Error('not find'))
+    } else {
+      // 指定为字符串,然后再转成一个对象,类型是不明确的要使用泛型,返回第一层+泛型,泛型的定义是一个类和之前的有所差距
+      const result = JSON.parse(res.result as string) as T
+      // 再判断返回的状态码进行处理,不是200都是失败
+      if (result.code === 200) {
+        return result as T
+      } else {
+        promptAction.openToast({ message: result.msg })
+        return Promise.reject(new Error(result.msg))
+      }
+    }
+  } catch (error) {
+    promptAction.openToast({ message: error })
+    return Promise.reject(error)
+  } finally {
+    // 销毁请求请求结束
+    httpRequest.destroy()
+  }
+}
+
+/**
+ * 静态封装使用
+ */
+export class Request {
+  /**
+   * Get请求封装
+   * @param url   请求地址
+   * @param data  携带数据
+   * @returns
+   */
+  static get<T extends Rsp>(url: string, data?: object): Promise<T> {
+    return requestHttp<T>(url, http.RequestMethod.GET, data)
+  }
+
+  /**
+   * Post请求封装
+   * @param url   请求地址
+   * @param data  携带数据
+   * @returns
+   */
+  static post<T extends Rsp>(url: string, data?: object): Promise<T> {
+    return requestHttp<T>(url, http.RequestMethod.POST, data)
+  }
+
+  /**
+   * Put请求封装
+   * @param url   请求地址
+   * @param data  携带数据
+   * @returns
+   */
+  static put<T extends Rsp>(url: string, data?: object): Promise<T> {
+    return requestHttp<T>(url, http.RequestMethod.PUT, data)
+  }
+
+  /**
+   * Delete请求封装
+   * @param url   请求地址
+   * @param data  携带数据
+   * @returns
+   */
+  static delete<T extends Rsp>(url: string, data?: object): Promise<T> {
+    return requestHttp<T>(url, http.RequestMethod.DELETE, data)
+  }
+}

+ 74 - 0
entry/src/main/ets/utils/Storage.ets

@@ -0,0 +1,74 @@
+// PreferenceManager.ets
+import preferences from '@ohos.data.preferences';
+import common from '@ohos.app.ability.common';
+
+export class Storage {
+  private static prefs: preferences.Preferences;
+
+  static async init(context: common.UIAbilityContext) {
+    if (!Storage.prefs) {
+      try {
+        Storage.prefs = await preferences.getPreferences(context, 'app_prefs');
+      } catch (error) {
+
+      }
+    }
+  }
+
+  /**
+   * 设置当前登录状态
+   * @param value
+   */
+  static async setLogin(value: boolean) {
+    try {
+      Storage.prefs.put("is_login", value).catch()
+      await Storage.prefs.flush()
+    } catch (e) {
+    }
+  }
+
+  /**
+   * 当前登录状态
+   *
+   * @returns
+   */
+  static isLogin(): boolean {
+    try {
+      return Storage.prefs.getSync('is_login', false) === true
+    } catch (error) {
+      return false
+    }
+  }
+
+  static async setToken(value: string) {
+    try {
+      Storage.prefs.put("token", value).catch()
+      await Storage.prefs.flush()
+    } catch (e) {
+    }
+  }
+
+  static getToken(): string {
+    try {
+      return Storage.prefs.getSync('token', "") as string
+    } catch (error) {
+      return ""
+    }
+  }
+
+  static async setUsername(value: string) {
+    try {
+      Storage.prefs.put("username", value).catch()
+      await Storage.prefs.flush()
+    } catch (e) {
+    }
+  }
+
+  static getUsername(): string {
+    try {
+      return Storage.prefs.getSync('username', "") as string
+    } catch (error) {
+      return ""
+    }
+  }
+}

+ 16 - 0
entry/src/main/ets/utils/SysUtils.ets

@@ -0,0 +1,16 @@
+import inputMethod from '@ohos.inputMethod';
+
+/**
+ * 隐藏键盘操作
+ */
+export function hideKeyboard() {
+  try {
+    const ctrl = inputMethod.getController()
+    if (ctrl) {
+      ctrl.stopInputSession(() => {
+      })
+    }
+  } catch (error) {
+    // 处理隐藏失败
+  }
+}

+ 12 - 0
entry/src/main/ets/vm/VMHome.ets

@@ -0,0 +1,12 @@
+@Observed
+export class VMHome {
+  tabIndex: number = 0
+
+  /**
+   * 更新当前选中状态
+   * @param index
+   */
+  updateTabIndex(index: number) {
+    this.tabIndex = index
+  }
+}

+ 24 - 0
entry/src/main/ets/vm/VMHomeTab.ets

@@ -0,0 +1,24 @@
+import { Storage } from '../utils/Storage'
+
+@Observed
+export class VMHomeTab {
+  // 顶部用户名
+  username: string = ""
+  // 是否刷新中
+  isRefreshing: boolean = false
+
+  /**
+   * 初始化首页数据
+   */
+  init() {
+    // 更新用户名
+    this.username = Storage.getUsername()
+  }
+
+  onRefresh() {
+    this.isRefreshing = true
+    setTimeout(() => {
+      this.isRefreshing = false
+    }, 3000)
+  }
+}

+ 53 - 0
entry/src/main/ets/vm/VMLogin.ets

@@ -0,0 +1,53 @@
+import { Loading } from '../components/loading/Loading'
+import { promptAction } from '@kit.ArkUI'
+import { hideKeyboard } from '../utils/SysUtils'
+import { ReqApi } from '../api/req/ReqApi'
+import { Storage } from '../utils/Storage'
+
+@Observed
+export class VMLogin {
+  // 登录类型
+  // 0-短信登录 1-密码登录
+  loginType: number = 0
+  // 手机号或账号
+  account: string = ""
+  // 验证码或密码
+  code: string = ""
+
+  setLoginType(type: number) {
+    this.loginType = type
+  }
+
+  login(skip: Function) {
+    if (this.account.trim() == "") {
+      const msg = this.loginType == 0 ? "请输入手机号" : "请输入用户名"
+      promptAction.openToast({ message: msg })
+      return
+    }
+    if (this.code == "") {
+      const msg = this.loginType == 0 ? "请输入验证码" : "请输入密码"
+      promptAction.openToast({ message: msg })
+      return
+    }
+    hideKeyboard()
+    Loading.showLoading({ text: '登录中...' })
+    ReqApi.login(this.account.trim(), this.code).then((rsp) => {
+      Storage.setLogin(true)
+      Storage.setToken(rsp.token)
+      Storage.setUsername(rsp.nickName)
+      Loading.hideLoading()
+      promptAction.openToast({ message: '登录成功' })
+      skip()
+    }).catch(() => {
+      Loading.hideLoading()
+    })
+  }
+
+  updateAccount(account: string) {
+    this.account = account
+  }
+
+  updateCode(code: string) {
+    this.code = code
+  }
+}

+ 55 - 0
entry/src/main/module.json5

@@ -0,0 +1,55 @@
+{
+  "module": {
+    "name": "entry",
+    "type": "entry",
+    "description": "$string:app_name",
+    "mainElement": "Entry",
+    "deviceTypes": [
+      "phone"
+    ],
+    "requestPermissions": [
+      {
+        "name": "ohos.permission.INTERNET"
+      }
+    ],
+    "deliveryWithInstall": true,
+    "installationFree": false,
+    "pages": "$profile:main_pages",
+    "abilities": [
+      {
+        "name": "Entry",
+        "srcEntry": "./ets/entry/Entry.ets",
+        "description": "$string:app_name",
+        "icon": "$media:layered_image",
+        "label": "$string:app_name",
+        "startWindowIcon": "$media:startIcon",
+        "startWindowBackground": "$color:start_window_background",
+        "exported": true,
+        "skills": [
+          {
+            "entities": [
+              "entity.system.home"
+            ],
+            "actions": [
+              "ohos.want.action.home"
+            ]
+          }
+        ]
+      }
+    ],
+    "extensionAbilities": [
+      {
+        "name": "EntryBackup",
+        "srcEntry": "./ets/entry/EntryBackup.ets",
+        "type": "backup",
+        "exported": false,
+        "metadata": [
+          {
+            "name": "ohos.extension.backup",
+            "resource": "$profile:backup_config"
+          }
+        ]
+      }
+    ]
+  }
+}

+ 8 - 0
entry/src/main/resources/base/element/color.json

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

+ 8 - 0
entry/src/main/resources/base/element/float.json

@@ -0,0 +1,8 @@
+{
+  "float": [
+    {
+      "name": "page_text_font_size",
+      "value": "50fp"
+    }
+  ]
+}

+ 8 - 0
entry/src/main/resources/base/element/string.json

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

BIN
entry/src/main/resources/base/media/background.png


+ 1 - 0
entry/src/main/resources/base/media/bell.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765422573627" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="36243" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M849.6 713.4c8.4-0.4 16.7 1.8 23.8 6.4-28.9-18.5-46.4-50.4-46.3-84.8V436c0-145.9-105.7-267.6-246.9-297.5v-7.2c0-37.1-30.1-67.1-67.2-67.1h-0.1c-37.1 0-67.3 30.1-67.3 67.2v7C304.3 168.4 198.7 290 198.7 436v199.1c0 35.7-18.6 66.9-46.4 84.8 7-4.6 15.4-6.9 23.8-6.4-24.7-0.9-45.5 18.4-46.4 43.1-0.9 24.7 18.4 45.5 43.1 46.4h676.6c24.7 0.1 44.8-20 44.9-44.7 0.1-24.8-19.9-44.9-44.7-44.9zM513 959.8c62 0 112.2-50.2 112.2-111.9H400.7c0 61.7 50.2 111.9 112.3 111.9z" fill="" p-id="36244"></path></svg>

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
entry/src/main/resources/base/media/bluetooth.svg


+ 1 - 0
entry/src/main/resources/base/media/code.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765420942026" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="18768" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M946.78 96.34V606q0 45.84-21.74 91.18a430.64 430.64 0 0 1-56.96 88 632.42 632.42 0 0 1-80.42 80.64A872.84 872.84 0 0 1 696 933.6a702.46 702.46 0 0 1-90.44 49.54q-43.88 19.68-76.96 27.04l-10.6 1.82-9.56-1.82q-33.9-7.38-78.7-27.04a762 762 0 0 1-93.04-49.54A871.26 871.26 0 0 1 242 865.78a655.88 655.88 0 0 1-83.04-80.64 429.06 429.06 0 0 1-59.1-88Q77.18 651.8 77.22 606V96.34l35.64-5.52L512.86 12l407.84 78.82 26 5.52zM513 85.78l-4.82-1L164.86 146.3v321.52H513v-382z m346.14 382H513v457.7a476.34 476.34 0 0 0 72.66-24.7 646.26 646.26 0 0 0 77.42-39.3 692 692 0 0 0 73.66-50.4 440.56 440.56 0 0 0 62.66-59.52 294.42 294.42 0 0 0 43.46-66 160.16 160.16 0 0 0 16.28-69.56v-148.18z" p-id="18769"></path></svg>

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
entry/src/main/resources/base/media/fingerprint.svg


BIN
entry/src/main/resources/base/media/foreground.png


+ 1 - 0
entry/src/main/resources/base/media/home.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765422836296" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="39038" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M1002.437349 459.841996 619.235686 61.738046C593.688908 36.191268 548.982047 0 512.790779 0c-36.191268 0-59.609148 17.031185-85.155925 42.577963l-404.490644 395.975052c-27.675676 40.449064-23.417879 40.449064-21.288981 61.738046 0 12.773389-4.257796 42.577963 42.577963 42.577963l85.155925 0 0 334.237006c0 72.382536 31.933472 146.893971 106.444906 146.893971l170.31185 0L406.345873 666.345114c0-36.191268 4.257796-42.577963 42.577963-42.577963l127.733888 0c38.320166 0 42.577963 6.386694 42.577963 42.577963L619.235686 1021.871102l170.31185 0c74.511435 0 106.444906-74.511435 106.444906-146.893971L895.992442 562.029106l85.155925 0c31.933472 2.128898 42.577963-29.804574 42.577963-42.577963C1023.72633 489.64657 1017.339636 479.002079 1002.437349 459.841996L1002.437349 459.841996z" p-id="39039"></path></svg>

+ 1 - 0
entry/src/main/resources/base/media/job_finish.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765424112593" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="71486" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M512 0C229.23 0 0 229.23 0 512s229.23 512 512 512 512-229.23 512-512S794.77 0 512 0z m295.53 339.55l-313.17 382-21.6 26.34a50.46 50.46 0 0 1-7.17 7.15c-0.65 0.52-1.3 1-2 1.51-1.08 0.79-2.19 1.52-3.32 2.22-0.57 0.35-1.15 0.69-1.73 1s-1.26 0.7-1.91 1c-1.2 0.61-2.43 1.18-3.67 1.69a51 51 0 0 1-5.05 1.74c-1.38 0.39-2.77 0.74-4.17 1a50.812 50.812 0 0 1-9.47 0.95h-0.07a51.39 51.39 0 0 1-7.19-0.5 49.67 49.67 0 0 1-20.53-7.8 48.89 48.89 0 0 1-4.11-3L200.19 589a50 50 0 0 1-7-70.37 50 50 0 0 1 70.37-7l124.91 102.46a50 50 0 0 0 70.36-7l271.36-331a50 50 0 0 1 70.37-7 50 50 0 0 1 6.97 70.46z" p-id="71487"></path></svg>

+ 1 - 0
entry/src/main/resources/base/media/job_ing.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765423977722" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="69237" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M512 0C230.4 0 0 230.4 0 512s230.4 512 512 512 512-230.4 512-512-230.4-512-512-512z m-8.533333 776.533333c0 8.533333-8.533333 17.066667-17.066667 17.066667l-102.4 59.733333c-8.533333 0-8.533333 8.533333-17.066667 8.533334S341.333333 853.333333 341.333333 844.8c-8.533333-17.066667 0-34.133333 8.533334-42.666667l25.6-8.533333c-119.466667-51.2-196.266667-170.666667-196.266667-290.133333s68.266667-230.4 179.2-281.6c17.066667-8.533333 34.133333 0 42.666667 17.066666 8.533333 17.066667 0 34.133333-17.066667 42.666667-85.333333 42.666667-145.066667 128-145.066667 221.866667 0 102.4 68.266667 196.266667 162.133334 230.4L375.466667 682.666667c-8.533333-17.066667 0-34.133333 8.533333-42.666667 17.066667-8.533333 34.133333 0 42.666667 8.533333l59.733333 102.4c17.066667 8.533333 17.066667 17.066667 17.066667 25.6z m162.133333 34.133334h-17.066667c-17.066667 0-25.6-8.533333-34.133333-17.066667-8.533333-17.066667 0-34.133333 17.066667-42.666667 85.333333-42.666667 145.066667-128 145.066666-221.866666 0-102.4-59.733333-196.266667-162.133333-230.4l25.6 42.666666c8.533333 17.066667 0 34.133333-17.066667 42.666667h-17.066666c-8.533333 8.533333-17.066667 0-25.6-8.533333l-51.2-110.933334c0-8.533333-8.533333-17.066667 0-25.6s8.533333-17.066667 17.066666-17.066666L657.066667 170.666667c17.066667-8.533333 34.133333 0 42.666666 17.066666 8.533333 17.066667 0 34.133333-17.066666 42.666667l-25.6 8.533333c110.933333 51.2 187.733333 162.133333 187.733333 281.6 0 128-68.266667 238.933333-179.2 290.133334z" fill="#2c2c2c" p-id="69238"></path></svg>

+ 1 - 0
entry/src/main/resources/base/media/job_todo.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765424065542" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="70311" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M512 0C229.234 0 0 229.234 0 512s229.234 512 512 512 512-229.234 512-512S794.766 0 512 0z m306.048 622.165h-380.7v-10.31h-3.826V231.153h64.725v326.3h319.815v64.711z" p-id="70312"></path></svg>

+ 1 - 0
entry/src/main/resources/base/media/jobs.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765423139807" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="48583" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M965.12 684.032c-11.264-18.944-25.6-37.888-43.008-54.784-16.896-16.384-35.328-31.232-55.808-43.52l34.304-34.304s49.152 0 73.728 24.576c24.576 24.576 24.576 73.728 24.576 73.728l-33.792 34.304M661.504 991.744H558.592V888.832l12.288-12.288c22.528 10.752 43.008 25.088 60.416 42.496 17.408 17.408 32.256 37.888 42.496 60.416l-12.288 12.288m274.944-279.552l-232.96 237.056a273.817 273.817 0 0 0-45.056-57.344c-17.408-17.408-37.376-32.768-58.368-45.056l237.568-233.472c21.504 10.24 40.96 24.064 57.856 40.448s31.232 37.376 40.96 58.368m-482.304 179.2c-0.512-12.8 76.288-94.208 166.4-185.344h-401.92c-21.504 0-38.912-17.408-38.912-38.912 0-21.504 17.408-38.912 38.912-38.912h454.144c7.168 0 13.824 2.048 19.456 5.12 78.848-78.848 155.648-153.6 190.976-187.904V90.624c0-47.104-38.4-85.504-85.504-85.504H111.104C64 5.12 25.6 43.52 25.6 90.624v842.24c0 47.104 38.4 85.504 85.504 85.504h343.552c0-47.104 0-109.056-0.512-126.976M178.176 258.048c0-21.504 17.408-38.912 38.912-38.912H673.28c21.504 0 38.912 17.408 38.912 38.912s-17.408 38.912-38.912 38.912H217.088c-21.504 0-38.912-17.408-38.912-38.912m1.536 206.336c0-21.504 17.408-38.912 38.912-38.912h454.144c21.504 0 38.912 17.408 38.912 38.912 0 21.504-17.408 38.912-38.912 38.912H219.136c-21.504 0-39.424-17.92-39.424-38.912" p-id="48584"></path></svg>

+ 7 - 0
entry/src/main/resources/base/media/layered_image.json

@@ -0,0 +1,7 @@
+{
+  "layered-image":
+  {
+    "background" : "$media:background",
+    "foreground" : "$media:foreground"
+  }
+}

+ 1 - 0
entry/src/main/resources/base/media/location.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765425546872" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="85717" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M702.932 777.584c-11.692-3.161-23.743 3.758-26.903 15.45-3.165 11.698 3.758 23.744 15.451 26.903 73.027 19.747 105.712 47.546 105.712 66.333 0 14.494-19.804 37.052-75.398 56.907-55.701 19.895-130.205 30.845-209.791 30.845-79.586 0-154.099-10.95-209.799-30.845-55.593-19.855-75.396-42.413-75.396-56.907 0-18.793 32.702-46.602 105.761-66.348 11.698-3.161 18.618-15.201 15.456-26.899-3.159-11.692-15.199-18.617-26.897-15.455-89.119 24.084-138.198 62.687-138.198 108.702 0 26.869 17.359 47.165 31.924 59.459 17.477 14.762 41.905 27.805 72.594 38.766 60.318 21.541 140.063 33.407 224.549 33.407 84.493 0 164.238-11.872 224.556-33.407 30.689-10.961 55.115-24.005 72.595-38.766 14.564-12.295 31.924-32.59 31.924-59.459 0-46-49.056-84.603-138.137-108.686v0zM422.048 826.725c23.419 26.842 56.222 42.223 90.118 42.223h0.005c34.028 0 66.802-15.506 90.080-42.569 7.059-7.696 67.087-73.789 127.916-160.351 88.146-125.43 132.837-229.369 132.837-308.923 0-47.367-9.283-93.344-27.597-136.64-17.684-41.803-42.986-79.343-75.212-111.563-32.219-32.218-69.751-57.526-111.554-75.202-43.302-18.315-89.278-27.603-136.639-27.603-47.367 0-93.344 9.289-136.641 27.603-41.802 17.678-79.342 42.985-111.561 75.202-32.219 32.226-57.526 69.759-75.202 111.563-18.315 43.297-27.603 89.273-27.603 136.64 0 79.552 44.724 183.524 132.929 309.029 61.247 87.146 121.682 153.568 128.124 160.59v0zM375.908 347.29c0-77.421 62.989-140.405 140.402-140.405 77.421 0 140.404 62.986 140.404 140.405 0 77.415-62.982 140.404-140.404 140.404-77.414 0-140.402-62.989-140.402-140.404v0zM375.908 347.29z" p-id="85718"></path></svg>

+ 1 - 0
entry/src/main/resources/base/media/message.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765423444842" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="55278" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M903.618 26.767c66.209 0 119.882 53.673 119.882 119.883v625.367c0 66.21-53.673 119.883-119.882 119.883H704.692a59.941 59.941 0 0 0-32.285 9.437l-143.946 92.018a29.97 29.97 0 0 1-32.591-0.199l-139.25-91.422a59.941 59.941 0 0 0-32.898-9.834h-202.34c-66.21 0-119.883-53.674-119.883-119.883V146.65c0-66.21 53.673-119.883 119.882-119.883h782.237z m-624.39 379.836c-38.623 0-69.932 31.31-69.932 69.932s31.309 69.931 69.931 69.931 69.932-31.31 69.932-69.931-31.31-69.932-69.932-69.932z m232.772 0c-38.622 0-69.932 31.31-69.932 69.932s31.31 69.931 69.932 69.931 69.932-31.31 69.932-69.931-31.31-69.932-69.932-69.932z m232.773 0c-38.623 0-69.932 31.31-69.932 69.932s31.31 69.931 69.932 69.931 69.931-31.31 69.931-69.931-31.309-69.932-69.931-69.932z" fill="#2c2c2c" p-id="55279"></path></svg>

+ 7 - 0
entry/src/main/resources/base/media/phone.svg

@@ -0,0 +1,7 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+        "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg t="1765419959302" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7619"
+     width="32" height="32">
+    <path d="M170.666667 0v967.111111h682.666666V0z m341.333333 910.222222a85.333333 85.333333 0 1 1 85.333333-85.333333A85.333333 85.333333 0 0 1 512 910.222222z m227.555556-227.555555H284.444444V113.777778h455.111112z"
+          fill="#333333" p-id="7620"></path>
+</svg>

+ 1 - 0
entry/src/main/resources/base/media/pwd.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765421245840" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23606" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M639.9 351.9C639.9 192.9 511.1 64 352 64S64.2 192.8 64.2 351.9c0 158.9 128.8 287.9 287.9 287.9 158.9-0.1 287.8-128.9 287.8-287.9z m-367.4 16.4c-50.4 0-91.3-40.9-91.3-91.3s40.9-91.3 91.3-91.3 91.3 40.9 91.3 91.3-40.9 91.3-91.3 91.3z" p-id="23607"></path><path d="M930 732.3L663.8 455l-43 71.6h0.7l253.4 266.3-1.8 27.6-45.9 1.8-237.7-250.4c-39.1 46-85.6 70.5-85.6 70.5l5.5 112 53.3 58.8H706L704.2 949l126.7 11s12.9-12.9 91.9-90c78.9-77.1 7.2-137.7 7.2-137.7z" p-id="23608"></path></svg>

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
entry/src/main/resources/base/media/qrcode.svg


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
entry/src/main/resources/base/media/settings.svg


BIN
entry/src/main/resources/base/media/startIcon.png


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
entry/src/main/resources/base/media/tips.svg


+ 1 - 0
entry/src/main/resources/base/media/user.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1765421135694" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21648" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32"><path d="M502.178909 38.632727c-131.072 0-237.521455 104.168727-237.521454 232.727273s106.402909 232.727273 237.521454 232.727273c131.165091 0 237.568-104.168727 237.568-232.727273s-106.309818-232.727273-237.568-232.727273z m0 0c-131.072 0-237.521455 104.168727-237.521454 232.727273s106.402909 232.727273 237.521454 232.727273c131.165091 0 237.568-104.168727 237.568-232.727273s-106.309818-232.727273-237.568-232.727273zM413.184 581.678545c-169.472 0-306.874182 134.609455-306.874182 300.590546v19.316364c0 67.909818 137.402182 67.956364 306.874182 67.956363h197.957818c169.425455 0 306.781091-2.513455 306.781091-67.956363v-19.316364c0-165.981091-137.355636-300.590545-306.781091-300.590546H413.184z m0 0" p-id="21649"></path></svg>

+ 3 - 0
entry/src/main/resources/base/profile/backup_config.json

@@ -0,0 +1,3 @@
+{
+  "allowToBackupRestore": true
+}

+ 7 - 0
entry/src/main/resources/base/profile/main_pages.json

@@ -0,0 +1,7 @@
+{
+  "src": [
+    "pages/PageSplash",
+    "pages/PageLogin",
+    "pages/PageHome"
+  ]
+}

+ 8 - 0
entry/src/main/resources/dark/element/color.json

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

+ 2 - 0
entry/src/mock/mock-config.json5

@@ -0,0 +1,2 @@
+{
+}

+ 35 - 0
entry/src/ohosTest/ets/test/Ability.test.ets

@@ -0,0 +1,35 @@
+import { hilog } from '@kit.PerformanceAnalysisKit';
+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);
+    })
+  })
+}

+ 5 - 0
entry/src/ohosTest/ets/test/List.test.ets

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

+ 11 - 0
entry/src/ohosTest/module.json5

@@ -0,0 +1,11 @@
+{
+  "module": {
+    "name": "entry_test",
+    "type": "feature",
+    "deviceTypes": [
+      "phone"
+    ],
+    "deliveryWithInstall": true,
+    "installationFree": false
+  }
+}

+ 5 - 0
entry/src/test/List.test.ets

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

+ 33 - 0
entry/src/test/LocalUnit.test.ets

@@ -0,0 +1,33 @@
+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);
+    });
+  });
+}

+ 23 - 0
hvigor/hvigor-config.json5

@@ -0,0 +1,23 @@
+{
+  "modelVersion": "6.0.1",
+  "dependencies": {
+  },
+  "execution": {
+    // "analyze": "normal",                     /* Define the build analyze mode. Value: [ "normal" | "advanced" | "ultrafine" | false ]. Default: "normal" */
+    // "daemon": true,                          /* Enable daemon compilation. Value: [ true | false ]. Default: true */
+    // "incremental": true,                     /* Enable incremental compilation. Value: [ true | false ]. Default: true */
+    // "parallel": true,                        /* Enable parallel compilation. Value: [ true | false ]. Default: true */
+    // "typeCheck": false,                      /* Enable typeCheck. Value: [ true | false ]. Default: false */
+    // "optimizationStrategy": "memory"         /* Define the optimization strategy. Value: [ "memory" | "performance" ]. Default: "memory" */
+  },
+  "logging": {
+    // "level": "info"                          /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
+  },
+  "debugging": {
+    // "stacktrace": false                      /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
+  },
+  "nodeOptions": {
+    // "maxOldSpaceSize": 8192                  /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/
+    // "exposeGC": true                         /* Enable to trigger garbage collection explicitly. Default: true*/
+  }
+}

+ 6 - 0
hvigorfile.ts

@@ -0,0 +1,6 @@
+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. */
+}

+ 28 - 0
oh-package-lock.json5

@@ -0,0 +1,28 @@
+{
+  "meta": {
+    "stableOrder": true,
+    "enableUnifiedLockfile": false
+  },
+  "lockfileVersion": 3,
+  "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
+  "specifiers": {
+    "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0",
+    "@ohos/hypium@1.0.24": "@ohos/hypium@1.0.24"
+  },
+  "packages": {
+    "@ohos/hamock@1.0.0": {
+      "name": "@ohos/hamock",
+      "version": "1.0.0",
+      "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==",
+      "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har",
+      "registryType": "ohpm"
+    },
+    "@ohos/hypium@1.0.24": {
+      "name": "@ohos/hypium",
+      "version": "1.0.24",
+      "integrity": "sha512-3dCqc+BAR5LqEGG2Vtzi8O3r7ci/3fYU+FWjwvUobbfko7DUnXGOccaror0yYuUhJfXzFK0aZNMGSnXaTwEnbw==",
+      "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.24.har",
+      "registryType": "ohpm"
+    }
+  }
+}

+ 10 - 0
oh-package.json5

@@ -0,0 +1,10 @@
+{
+  "modelVersion": "6.0.1",
+  "description": "Please describe the basic information.",
+  "dependencies": {
+  },
+  "devDependencies": {
+    "@ohos/hypium": "1.0.24",
+    "@ohos/hamock": "1.0.0"
+  }
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно