This commit is contained in:
lixiao 2025-07-02 17:39:35 +08:00
commit 04aebbe02d
55 changed files with 1579 additions and 0 deletions

11
.gitignore vendored Normal file
View File

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

10
AppScope/app.json5 Normal file
View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

49
build-profile.json5 Normal file
View File

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

6
entry/.gitignore vendored Normal file
View File

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

13
entry/build-profile.json5 Normal file
View File

@ -0,0 +1,13 @@
{
"apiType": "stageMode",
"buildOption": {
},
"targets": [
{
"name": "default",
},
{
"name": "ohosTest",
}
]
}

6
entry/hvigorfile.ts Normal file
View File

@ -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. */
}

10
entry/oh-package.json5 Normal file
View File

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

View File

@ -0,0 +1,78 @@
export enum CusButtonType {
Info,
Primary,
}
export enum CusButtonSize {
Small,
Normal,
Large
}
const ButtonSize: Record<number, Array<number>> = {
0: [8, 54],
1: [12, 54],
2: [16, 54],
}
@Extend(Button)
function button(size: CusButtonSize, block: boolean) {
.padding(block ? {
top: ButtonSize[size][0],
bottom: ButtonSize[size][0]
} : {
left: ButtonSize[size][1],
right: ButtonSize[size][1],
top: ButtonSize[size][0],
bottom: ButtonSize[size][0]
}).fontSize(18).type(ButtonType.Normal)
}
@Extend(Button)
function info(size: CusButtonSize, block: boolean) {
.backgroundColor(0xffffff)
.fontColor(0x0D419D)
.border({
width: 1,
color: 0x0D419D,
radius: 6
})
.button(size, block)
}
@Extend(Button)
function primary(size: CusButtonSize, block: boolean) {
.backgroundColor(0x0D419D)
.fontColor(0xffffff)
.border({
width: 1,
color: 0x0D419D,
radius: 6
})
.button(size, block)
}
@Component
export default struct CusButton {
label: string = ""
buttonType: CusButtonType = CusButtonType.Info
buttonSize: CusButtonSize = CusButtonSize.Normal
block: boolean = false
build() {
if (this.block) {
if (this.buttonType === CusButtonType.Info) {
Button(this.label).info(this.buttonSize, this.block).width("100%")
} else {
Button(this.label).primary(this.buttonSize, this.block).width("100%")
}
} else {
if (this.buttonType === CusButtonType.Info) {
Button(this.label).info(this.buttonSize, this.block)
} else {
Button(this.label).primary(this.buttonSize, this.block)
}
}
}
}

View File

@ -0,0 +1,55 @@
import CusButton, { CusButtonType } from './Button'
interface Button {
label: string
type: CusButtonType
click: () => void
}
@CustomDialog
export default struct Exiting {
private controller: CustomDialogController
button: Button[] = []
message: string[] = []
build() {
Column() {
Row() {
Text("提示").fontSize(28).fontColor(0xffffff)
Blank()
Image($rawfile("img/close.png")).width(18)
}
.width("100%")
.linearGradient({
angle: 90,
direction: GradientDirection.Right,
colors: [[0x2876D6, 0.0], [0x2876D6, 1.0]]
})
.padding({ left: 24, right: 24, top: 18, bottom: 18 })
.width("100%")
.borderRadius({ topLeft: 6, topRight: 6 })
Column() {
Image($rawfile('img/warning.png')).width(64).margin({ bottom: 40 })
ForEach(this.message, (item: string, index: number) => {
Text(item).fontSize(18).fontColor(0x3F4042).margin({ bottom: index < this.message.length - 1 ? 8 : 40 })
})
Row() {
ForEach(this.button, (item: Button, index: number) => {
CusButton({
label: item.label,
buttonType: item.type
})
.margin({ right: index < this.button.length - 1 ? 8 : 0, left: index > 0 ? 8 : 0 })
.onClick(() => {
item.click()
})
})
}.width("100%").justifyContent(FlexAlign.Center)
}.padding({ top: 42, bottom: 42, left: 120, right: 120 }).alignItems(HorizontalAlign.Center).width("100%")
}
.backgroundColor(0xffffff)
.borderRadius(6).width("50%")
}
}

View File

@ -0,0 +1,13 @@
@Component
export default struct Footer {
build() {
Row() {
Text("版权所有:多伦科技股份有限公司").fontSize(14).letterSpacing(1).fontColor(0xffffff)
}
.width("100%")
.height(52)
.backgroundColor(0x0D419D)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
}
}

View File

@ -0,0 +1,84 @@
import window from '@ohos.window'
import Exiting from './Dialog'
import router from '@ohos.router'
import { CusButtonType } from './Button'
@Component
export default struct Header {
@State BarHeight: number = 0
@StorageProp("line") line: string = "1"
private controller: CustomDialogController = new CustomDialogController({
builder: Exiting({
button: [
{
label: "确认",
type: CusButtonType.Primary,
click: () => {
this.controller.close()
router.back({
url: "pages/Home"
})
}
},
{
label: "取消",
type: CusButtonType.Info,
click: () => {
this.controller.close()
}
}
],
message: [
"您是否确认退出本次查验?",
"点击确定则退出本次查验,请将车辆使出查验区"
]
}),
customStyle: true,
})
showFun: boolean = true
async aboutToAppear(): Promise<void> {
let win = await window.getLastWindow(getContext(this))
this.BarHeight = px2vp(win.getWindowAvoidArea(window.AvoidAreaType.TYPE_SYSTEM).topRect.height)
win.setWindowSystemBarProperties({
statusBarColor: "#0D419D",
statusBarContentColor: "#ffffff"
})
}
build() {
Column() {
Row() {
}.width("100%").height(this.BarHeight)
if (this.showFun) {
Flex({ justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Center }) {
Image($rawfile('img/logo_en.png')).height(36)
Text("小车智能查验装备").fontSize(24).fontColor(0xffffff)
Row() {
Text(this.line + "号线")
.fontColor(0xffffff)
.padding({ top: 12, bottom: 12, left: 24, right: 24 })
.margin({ right: 12 })
.linearGradient({
angle: 90,
direction: GradientDirection.Right,
colors: [[0X5596FF, 0.0], [0X5FCBFF, 1.0]]
})
.borderRadius(6)
Button({ type: ButtonType.Normal }) {
Row() {
Image($rawfile('img/exit.png')).margin({ right: 6 }).height(16)
Text("退出").margin({ left: 6 }).fontSize(16).fontColor(0x8A8C8F)
}.alignItems(VerticalAlign.Center)
}.backgroundColor(0xffffff).borderRadius(6).padding(12).onClick(() => {
this.controller.open()
})
}
}.padding({ left: 30, right: 30, top: 16, bottom: 16 })
}
}.width("100%").backgroundColor(0x0D419D)
}
}

View File

@ -0,0 +1,48 @@
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 { requestPermission } from '../utils/system';
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');
}
async onWindowStageCreate(windowStage: window.WindowStage): Promise<void> {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
let window = await windowStage.getMainWindow()
window.setWindowSystemBarEnable(["status"])
window.setWindowLayoutFullScreen(true)
requestPermission(this.context, ['ohos.permission.CAMERA', 'ohos.permission.FILE_ACCESS_MANAGER'])
.then(() => {
windowStage.loadContent('pages/Login', (err) => {
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.');
});
})
}
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

@ -0,0 +1,84 @@
import window from '@ohos.window'
import Footer from '../components/Footer'
import router from '@ohos.router'
import Header from '../components/Header'
import CusButton, { CusButtonSize, CusButtonType } from '../components/Button'
@Entry
@Component
struct Home {
aboutToAppear(): void {
window.getLastWindow(getContext(this)).then(win => {
win.setWindowSystemBarProperties({
statusBarColor: "#0D419D",
statusBarContentColor: "#ffffff"
})
})
}
build() {
Column() {
Header({
showFun: false
})
Column() {
Image($rawfile('img/logo_cn.png'))
.backgroundImageSize(ImageSize.Contain)
.height(32)
.margin({ bottom: "12%" })
Text("小车智能查验设备")
.focusable(true)
.defaultFocus(true)
.margin({ bottom: 12 })
.fontSize(36)
.fontWeight(700)
Text("版本1.0.0").margin({ bottom: "15%" })
Text("1号查验线机器人")
.fontSize(24)
.fontColor(0xffffff)
.padding({ top: 30, bottom: 30 })
.borderRadius(6)
.linearGradient({
angle: 90,
direction: GradientDirection.Right,
colors: [[0X5596FF, 0.0], [0X5FCBFF, 1.0]]
})
.textAlign(TextAlign.Center)
.width("100%")
.margin({ bottom: "10%" })
Row() {
CusButton({
label: "登出",
buttonSize: CusButtonSize.Large,
block: true
}).layoutWeight(1).margin({ right: 12 }).onClick(() => {
router.back({
url: "pages/Login"
})
})
CusButton({
label: "确认",
buttonType: CusButtonType.Primary,
block: true,
buttonSize: CusButtonSize.Large
}).layoutWeight(1).margin({ left: 12 }).onClick(() => {
// router.pushUrl({
// url: "pages/ProjectCheck"
// }, router.RouterMode.Single)
// router.pushUrl({
// url: "pages/Scan"
// }, router.RouterMode.Single)
router.pushUrl({
url: "pages/Sign"
}, router.RouterMode.Single)
})
}.width("100%")
}.layoutWeight(1).padding({ left: "36%", right: "36%", top: "10%" })
Footer()
}.width('100%').height('100%').backgroundColor(0xe7f3ff)
}
}

View File

@ -0,0 +1,194 @@
import window from '@ohos.window'
import router from '@ohos.router'
@Component
struct InputComponent {
@Link value: string
@State focus: boolean = false
placeholder: string = ''
label: string = ''
type: InputType = InputType.Normal
build() {
Column() {
Text(this.label).fontColor(0x3F4042).fontSize(16).margin({ bottom: 8 })
TextInput({
text: $$this.value,
placeholder: this.placeholder
})
.fontSize(20)
.padding(12)
.defaultFocus(false)
.backgroundColor(0xffffff)
.focusable(true)
.onFocus(() => {
this.focus = true
})
.onBlur(() => {
this.focus = false
})
.type(this.type)
.border({
width: 1,
color: this.focus ? 0xB4CFFA : 0xE2E3E2,
style: BorderStyle.Solid,
radius: 6
})
.placeholderColor(0xD8D8D8)
}.alignItems(HorizontalAlign.Start)
}
}
@Component
struct SelectComponent {
@Link value: number
@State focus: boolean = false
@Prop options: SelectOption[] = []
@State selected: number = -1
placeholder: string = ''
label: string = ''
build() {
Column() {
Text(this.label).fontColor(0x3F4042).fontSize(16).margin({ bottom: 8 })
Select(this.options)
.font({
size: 16
})
.backgroundColor(0xffffff)
.value($$this.value)
.selected(this.selected)
.padding(12)
.defaultFocus(false)
.focusable(true)
.onFocus(() => {
this.focus = true
})
.onBlur(() => {
this.focus = false
})
.border({
width: 1,
color: this.focus ? 0xB4CFFA : 0xE2E3E2,
style: BorderStyle.Solid,
radius: 6
})
.width("100%")
.height(44)
}.alignItems(HorizontalAlign.Start)
}
}
@Entry
@Component
struct Index {
@State account: string = ''
@State password: string = ''
@State line: number = -1
@State options: SelectOption[] = [
{ value: "1号线" },
{ value: "2号线" },
{ value: "3号线" }
]
aboutToAppear(): void {
window.getLastWindow(getContext(this)).then(win => {
win.setWindowSystemBarProperties({
statusBarColor: "transparent",
statusBarContentColor: "#000000"
})
})
}
login() {
router.pushUrl({
url: "pages/Home"
}, router.RouterMode.Single)
}
build() {
Row() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center }) {
Column() {
Image($rawfile('img/logo_cn.png'))
.backgroundImageSize(ImageSize.Contain)
.height(32)
.margin({ bottom: "10%" })
Text("小车智能查验设备")
.focusable(true)
.defaultFocus(true)
.margin({ bottom: 12 })
.fontSize(36)
.fontWeight(700)
Text("版本1.0.0").margin({ bottom: "10%" })
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween }) {
InputComponent({
label: '请输入机器人账号',
value: this.account
})
InputComponent({
label: '请输入登录密码',
value: this.password,
type: InputType.Password
})
SelectComponent({
label: "请选择检测路线",
value: this.line,
options: this.options
})
Button("登录")
.fontSize(20)
.padding(12)
.backgroundColor(0x0D419D)
.fontColor(0xffffff)
.type(ButtonType.Normal)
.border({
width: 1,
color: 0x0D419D,
style: BorderStyle.Solid,
radius: 6
})
.margin({ top: 12 })
.width("100%")
.onClick(() => {
this.login()
})
}.layoutWeight(1)
}
.padding(40)
.alignItems(HorizontalAlign.Center)
.height('100%')
.width("100%")
.backgroundColor('rgba(255,255,255,0.5)')
.backgroundBlurStyle(BlurStyle.Regular)
.borderRadius(18)
.border({
width: 2,
color: 0xffffff,
style: BorderStyle.Solid
})
Text("版权所有:多伦科技股份有限公司")
.fontSize(14)
.padding({ top: 2, bottom: 2 })
.margin({ top: "15%", bottom: "10%" })
}
.margin({ right: '12%' })
.padding({
top: "12%"
})
.height('100%')
.width("30%")
}
.width('100%')
.height('100%')
.backgroundImage($rawfile('img/login/background.png'))
.backgroundImageSize(ImageSize.Cover)
.justifyContent(FlexAlign.End)
}
}

View File

@ -0,0 +1,25 @@
import Footer from '../components/Footer'
import window from '@ohos.window'
import Header from '../components/Header'
@Entry
@Component
struct ProjectCheck {
aboutToAppear(): void {
}
build() {
Column() {
Header()
Row() {
Image($rawfile('img/check/scan.png')).layoutWeight(1).margin({ right: 32 }).height("100%")
Column() {
}.width("33%")
}.layoutWeight(1).width("100%").padding({ left: 32, top: 40, right: 32, bottom: 40 }).backgroundColor(0xd7ebfd)
Footer()
}.width('100%').height('100%')
}
}

View File

@ -0,0 +1,56 @@
import { CameraUtils } from '../utils/cameraUtils';
import Header from '../components/Header';
import Footer from '../components/Footer';
import common from '@ohos.app.ability.common';
@Entry
@Component
struct Scan {
@State showVideo: boolean = false
private xComponentController: XComponentController = new XComponentController()
private cameraUtils: CameraUtils = new CameraUtils(getContext(this) as common.UIAbilityContext)
private surfaceId: string = ""
aboutToAppear(): void {
}
aboutToDisappear(): void {
this.cameraUtils.destroy()
}
build() {
Column() {
Header()
Row() {
Row() {
if (this.showVideo) {
XComponent({
id: "cameraPreview",
type: XComponentType.SURFACE,
controller: this.xComponentController
}).onLoad(() => {
this.surfaceId = this.xComponentController.getXComponentSurfaceId()
this.cameraUtils.init(this.surfaceId).then(() => {
this.cameraUtils.startPreview()
})
}).width("100%").height("100%").renderFit(RenderFit.RESIZE_CONTAIN)
} else {
Image($rawfile('img/check/scan.png')).width("100%").height("100%")
}
}.layoutWeight(1).margin({ right: 32 })
Column() {
Text("请扫描受理凭证").fontSize(36).fontColor(0x161B21).fontWeight(700).margin({ bottom: 64 })
Text("识别结果").fontSize(24).fontColor(0x161B21).fontWeight(700).margin({ bottom: 30 })
RowSplit() {
Text("流水号").width("16%").fontWeight(700).fontSize(18).fontColor(0x161B21)
Text("1293982729381").layoutWeight(1).fontSize(18).fontColor(0x102A9A).padding({ left: 20 })
}.resizeable(false).borderColor(0xAEC4E8)
}.width("33%").height("100%").alignItems(HorizontalAlign.Start).justifyContent(FlexAlign.Start)
}.layoutWeight(1).width("100%").padding({ left: 32, top: 54, right: 32, bottom: 54 }).backgroundColor(0xd7ebfd)
Footer()
}.width('100%').height('100%')
}
}

View File

@ -0,0 +1,95 @@
import CusButton, { CusButtonType } from '../components/Button'
import Footer from '../components/Footer'
import Header from '../components/Header'
@Entry
@Component
struct Sign {
@State base64: string = ""
private isReady: boolean = false
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D()
private isStart: boolean = false
onStart(event: TouchEvent) {
if (!this.isReady) {
return
}
this.isStart = true
this.context.beginPath()
this.context.moveTo(event.touches[0].x, event.touches[0].y)
this.context.strokeStyle = "#000000"
this.context.lineWidth = 5
}
onMove(event: TouchEvent) {
if (!this.isReady || !this.isStart) {
return
}
this.context.lineTo(event.touches[0].x, event.touches[0].y)
this.context.stroke()
}
onStop(event: TouchEvent) {
if (!this.isReady || !this.isStart) {
return
}
this.context.closePath()
}
clear() {
this.base64 = ""
this.context.clearRect(0, 0, this.context.width, this.context.height)
this.context.fillStyle = "#ffffff"
this.context.fillRect(0, 0, this.context.width, this.context.height)
}
submit() {
this.base64 = this.context.toDataURL("image/jpeg", 0.92)
}
build() {
Column() {
Header()
Column() {
Text("车主签名").fontSize(32).fontColor(0x161B21).fontWeight(700).margin({ top: 36, bottom: 36 })
Canvas(this.context)
.backgroundColor(0xffffff)
.layoutWeight(1)
.width("100%")
.onReady(() => {
this.isReady = true
this.context.fillStyle = "#ffffff"
this.context.fillRect(0, 0, this.context.width, this.context.height)
})
.onTouch(event => {
switch (event.type) {
case TouchType.Down:
this.onStart(event)
break
case TouchType.Up:
this.onStop(event)
break
case TouchType.Move:
this.onMove(event)
break
case TouchType.Cancel:
this.onStop(event)
break
default:
return
}
})
Row() {
CusButton({ label: "确认", buttonType: CusButtonType.Primary }).margin({ right: 12 }).onClick(() => {
this.submit()
})
CusButton({ label: "重签" }).margin({ left: 12 }).onClick(() => {
this.clear()
})
}.margin({ top: 36, bottom: 36 }).width("100%").justifyContent(FlexAlign.Center)
}.layoutWeight(1).alignItems(HorizontalAlign.Start).padding({ left: 180, right: 180 })
Footer()
}.width("100%").height("100%").backgroundColor(0xe6f2ff)
}
}

View File

@ -0,0 +1,13 @@
import Footer from '../components/Footer'
import Header from '../components/Header'
@Entry
@Component
struct Waiting {
build() {
Column() {
Header()
Footer()
}.height("100%").width("100%")
}
}

View File

@ -0,0 +1,97 @@
import common from '@ohos.app.ability.common'
import camera from '@ohos.multimedia.camera'
import image from '@ohos.multimedia.image'
import util from '@ohos.util'
export class CameraUtils {
private manager: camera.CameraManager
private device: camera.CameraDevice
private ability: camera.CameraOutputCapability
private cameraInput?: camera.CameraInput
private photoOutput: camera.PhotoOutput | undefined = undefined;
private previewOutput: camera.PreviewOutput | undefined = undefined;
private session: camera.CaptureSession
private imageReceiver: image.ImageReceiver
private takeCallback?: (base64: string) => void
constructor(context: common.UIAbilityContext) {
this.manager = camera.getCameraManager(context)
this.device = this.getUsbCamera()
this.ability = this.getCameraAbility(this.device)
this.imageReceiver = image.createImageReceiver(this.ability.photoProfiles[0].size.width, this.ability.photoProfiles[0].size.height, image.ImageFormat.JPEG, 8)
this.session = this.manager.createCaptureSession();
this.imageReceiver.on("imageArrival", async () => {
let img: image.Image = await this.imageReceiver.readNextImage()
const imagePacker = image.createImagePacker();
let component = await img.getComponent(image.ComponentType.JPEG)
let source = image.createImageSource(component.byteBuffer)
const options: image.PackingOption = {
format: "image/jpeg",
quality: 100
};
const arrayBuffer = await imagePacker.packing(source, options);
let base64 = new util.Base64Helper().encodeToStringSync(new Uint8Array(arrayBuffer))
img.release()
this.takeCallback?.(base64)
this.takeCallback = undefined
})
}
private getUsbCamera(): camera.CameraDevice {
let list = this.manager.getSupportedCameras()
let device: camera.CameraDevice = list.find(item => item.connectionType === camera.ConnectionType.CAMERA_CONNECTION_USB_PLUGIN)!
return device
}
private getCameraAbility(cameraDevice: camera.CameraDevice): camera.CameraOutputCapability {
return this.manager.getSupportedOutputCapability(cameraDevice)
}
async init(surfaceId: string) {
try {
this.cameraInput = this.manager.createCameraInput(this.device);
this.cameraInput?.open()
let photoSurfaceId: string = await this.imageReceiver.getReceivingSurfaceId()
this.photoOutput = this.manager.createPhotoOutput(this.ability.photoProfiles[0], photoSurfaceId)
this.previewOutput = this.manager.createPreviewOutput(this.ability.previewProfiles[0], surfaceId)
this.session.beginConfig()
this.session.addInput(this.cameraInput!)
this.session.addOutput(this.previewOutput)
this.session.addOutput(this.photoOutput)
await this.session.commitConfig()
} catch (e) {
console.log("error", JSON.stringify(e))
}
}
destroy() {
this.session.release()
this.cameraInput?.close()
this.imageReceiver.release()
this.previewOutput?.release()
this.photoOutput?.release()
}
async startPreview() {
return this.session.start()
}
async takePhoto() {
return new Promise<string>((resolve, reject) => {
try {
let photoSetting: camera.PhotoCaptureSetting = {
rotation: camera.ImageRotation.ROTATION_0,
quality: camera.QualityLevel.QUALITY_LEVEL_MEDIUM,
mirror: false
}
this.photoOutput?.capture(photoSetting)
this.takeCallback = (base64: string) => {
resolve(base64)
}
} catch (error) {
reject(error)
console.log("err", JSON.stringify(error))
}
})
}
}

View File

@ -0,0 +1,73 @@
import common from '@ohos.app.ability.common'
import fs from '@ohos.file.fs';
import zlib from '@ohos.zlib';
async function compressFileToCache(input: string, output: string, context: common.UIAbilityContext,): Promise<string> {
if (!fs.accessSync(input)) {
return ""
}
const tempDir = context.cacheDir + '/' + output
if (fs.statSync(input).isDirectory()) {
fs.listFileSync(input).forEach(name => {
fs.copyFileSync(input + '/' + name, tempDir + '/' + name)
})
await zlib.compressFile(tempDir, tempDir + '.zip', {
level: zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION,
memLevel: zlib.MemLevel.MEM_LEVEL_DEFAULT,
strategy: zlib.CompressStrategy.COMPRESS_STRATEGY_DEFAULT_STRATEGY
})
fs.rmdirSync(context.cacheDir + '/' + output)
return tempDir + '.zip'
} else {
const tempDir = context.cacheDir + '/' + output
fs.copyFileSync(input, output)
await zlib.compressFile(tempDir, tempDir + '.zip', {
level: zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION,
memLevel: zlib.MemLevel.MEM_LEVEL_DEFAULT,
strategy: zlib.CompressStrategy.COMPRESS_STRATEGY_DEFAULT_STRATEGY
})
fs.unlinkSync(context.cacheDir + '/' + output)
return tempDir + '.zip'
}
}
export class UsbUtils {
private context: common.UIAbilityContext
constructor(context: common.UIAbilityContext) {
this.context = context
}
getUsbDiskPath() {
let path = ""
try {
path = fs.listFileSync("/mnt/data/external")[0]
} catch (error) {
console.log("err", JSON.stringify(error))
}
return '/mnt/data/external' + '/' + path
}
async copyTrackToUsb() {
try {
let path = this.getUsbDiskPath()
let trackPath = await compressFileToCache('/data/log/duolun/logs', "track", this.context)
fs.copyFileSync(trackPath, path + '/' + "track.zip")
fs.unlinkSync(trackPath)
} catch (error) {
console.log("err", JSON.stringify(error))
}
}
async copyLogToUsb() {
try {
let path = this.getUsbDiskPath()
let logPath = await compressFileToCache('/data/log/hilog', "logs", this.context)
fs.copyFileSync(logPath, path + '/' + "log.zip")
fs.unlinkSync(logPath)
} catch (error) {
console.log("err", JSON.stringify(error))
}
}
}

View File

@ -0,0 +1,20 @@
import common from '@ohos.app.ability.common';
import abilityAccessCtrl, { Permissions } from '@ohos.abilityAccessCtrl';
export function requestPermission(context: common.UIAbilityContext, permissions: Permissions[], autoToSetting: boolean = false): Promise<void> {
let manager = abilityAccessCtrl.createAtManager();
return manager.requestPermissionsFromUser(context, permissions).then((data): Promise<void> => {
let status = data.authResults
for (let i = 0; i < status.length; i++) {
if (status[i] == 2) {
if (autoToSetting) {
} else {
return Promise.reject()
}
}
}
return Promise.resolve()
})
}

View File

@ -0,0 +1,81 @@
{
"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.ets",
"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"
]
}
]
}
],
"requestPermissions": [
{
"name": "ohos.permission.CAMERA"
},
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.FILE_ACCESS_MANAGER"
},
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC",
},
{
"name": "ohos.permission.STORAGE_MANAGER"
},
{
"name": "ohos.permission.WRITE_AUDIO"
},
{
"name": "ohos.permission.READ_AUDIO"
},
{
"name": "ohos.permission.READ_DOCUMENT"
},
{
"name": "ohos.permission.WRITE_DOCUMENT"
},
{
"name": "ohos.permission.MEDIA_LOCATION"
},
{
"name": "ohos.permission.WRITE_MEDIA"
},
{
"name": "ohos.permission.READ_MEDIA"
},
{
"name": "ohos.permission.READ_IMAGEVIDEO"
},
{
"name": "ohos.permission.WRITE_IMAGEVIDEO"
}
]
}
}

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,10 @@
{
"src": [
"pages/Login",
"pages/Home",
"pages/Scan",
"pages/ProjectCheck",
"pages/Waiting",
"pages/Sign"
]
}

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

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

View File

@ -0,0 +1,35 @@
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

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

View File

@ -0,0 +1,49 @@
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) => {
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.');
});
}
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

@ -0,0 +1,17 @@
@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

@ -0,0 +1,50 @@
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';
const moduleName = abilityDelegatorArguments.parameters['-m'];
let lMonitor: AbilityDelegatorRegistry.AbilityMonitor = {
abilityName: testAbilityName,
onAbilityCreate: onAbilityCreateCallback,
moduleName: moduleName
};
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
const want: Want = {
bundleName: bundleName,
abilityName: testAbilityName,
moduleName: moduleName
};
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

@ -0,0 +1,36 @@
{
"module": {
"name": "entry_test",
"type": "feature",
"description": "$string:module_test_desc",
"mainElement": "TestAbility",
"deviceTypes": [
"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

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

View File

@ -0,0 +1,16 @@
{
"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.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

View File

@ -0,0 +1,22 @@
{
"hvigorVersion": "3.2.4",
"dependencies": {
"@ohos/hvigor-ohos-plugin": "3.2.4"
},
"execution": {
// "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */
// "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 */
},
"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": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */
}
}

1
hvigor/hvigor-wrapper.js Normal file

File diff suppressed because one or more lines are too long

6
hvigorfile.ts Normal file
View File

@ -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. */
}

54
hvigorw Normal file
View File

@ -0,0 +1,54 @@
#!/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
#NODE_OPTS="--max-old-space-size=4096"
fail() {
echo "$*"
exit 1
}
set_executable_node() {
EXECUTABLE_NODE="${NODE_HOME}/bin/node"
if [ -x "$EXECUTABLE_NODE" ]; then
return
fi
EXECUTABLE_NODE="${NODE_HOME}/node"
if [ -x "$EXECUTABLE_NODE" ]; then
return
fi
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"
}
# Determine node to start hvigor wrapper script
if [ -n "${NODE_HOME}" ]; then
set_executable_node
else
EXECUTABLE_NODE="node"
command -v ${EXECUTABLE_NODE} &> /dev/null || fail "ERROR: NODE_HOME not set and 'node' command not found"
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
if [ -z "${NODE_OPTS}" ]; then
NODE_OPTS="--"
fi
# start hvigor-wrapper script
exec "${EXECUTABLE_NODE}" "${NODE_OPTS}" \
"${HVIGOR_WRAPPER_SCRIPT}" "$@"

54
hvigorw.bat Normal file
View File

@ -0,0 +1,54 @@
@rem
@rem ----------------------------------------------------------------------------
@rem Hvigor startup script for Windows, version 1.0.0
@rem
@rem Required ENV vars:
@rem ------------------
@rem NODE_HOME - location of a Node home dir
@rem or
@rem Add %NODE_HOME%/bin to the PATH environment variable
@rem ----------------------------------------------------------------------------
@rem
@echo off
@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%
set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js
set NODE_EXE=node.exe
@rem set NODE_OPTS="--max-old-space-size=4096"
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
if not defined NODE_OPTS set NODE_OPTS="--"
@rem Find node.exe
if defined NODE_HOME (
set NODE_HOME=%NODE_HOME:"=%
set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE%
)
%NODE_EXE% --version >NUL 2>&1
if "%ERRORLEVEL%" == "0" (
"%NODE_EXE%" "%NODE_OPTS%" "%WRAPPER_MODULE_PATH%" %*
) else if exist "%NODE_EXE_PATH%" (
"%NODE_EXE%" "%NODE_OPTS%" "%WRAPPER_MODULE_PATH%" %*
) else (
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.
)
if "%ERRORLEVEL%" == "0" (
if "%OS%" == "Windows_NT" endlocal
) else (
exit /b %ERRORLEVEL%
)

13
oh-package-lock.json5 Normal file
View File

@ -0,0 +1,13 @@
{
"lockfileVersion": 1,
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
"specifiers": {
"@ohos/hypium@1.0.13": "@ohos/hypium@1.0.13"
},
"packages": {
"@ohos/hypium@1.0.13": {
"resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.13.tgz",
"integrity": "sha512-d0+XvDeAYk5Vgl6JQ8Q1G+NPmTyJI8qgZ1PwPfcUbx/dfyKVAAv9lz1XtVNhYypyWEKqAzu8zMAC9GuHo2Y53Q=="
}
}
}

13
oh-package.json5 Normal file
View File

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