正在显示
39 个修改的文件
包含
1148 行增加
和
193 行删除
不能预览此文件类型
| @@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
| 3 | "bundleName": "com.example.fireMaintenanceAssistant", | 3 | "bundleName": "com.example.fireMaintenanceAssistant", |
| 4 | "vendor": "example", | 4 | "vendor": "example", |
| 5 | "versionCode": 1000000, | 5 | "versionCode": 1000000, |
| 6 | - "versionName": "1.0.0", | 6 | + "versionName": "1.0.1", |
| 7 | "icon": "$media:app_icon", | 7 | "icon": "$media:app_icon", |
| 8 | "label": "$string:app_name" | 8 | "label": "$string:app_name" |
| 9 | } | 9 | } |
不能预览此文件类型
不能预览此文件类型
不能预览此文件类型
| @@ -273,6 +273,7 @@ export interface ItemList { | @@ -273,6 +273,7 @@ export interface ItemList { | ||
| 273 | proportion: string; | 273 | proportion: string; |
| 274 | state: string; | 274 | state: string; |
| 275 | record: recordType; | 275 | record: recordType; |
| 276 | + cosKey: string | null; | ||
| 276 | } | 277 | } |
| 277 | 278 | ||
| 278 | export interface recordType { | 279 | export interface recordType { |
| @@ -10,6 +10,8 @@ export default struct AddPersonDialog { | @@ -10,6 +10,8 @@ export default struct AddPersonDialog { | ||
| 10 | personName: '', | 10 | personName: '', |
| 11 | idNo: '' | 11 | idNo: '' |
| 12 | } | 12 | } |
| 13 | + //确认添加后的回调 | ||
| 14 | + onChange: () => void = () => {} | ||
| 13 | build() { | 15 | build() { |
| 14 | Column(){ | 16 | Column(){ |
| 15 | Text('添加人员').margin({top: 20}) | 17 | Text('添加人员').margin({top: 20}) |
| @@ -40,6 +42,7 @@ export default struct AddPersonDialog { | @@ -40,6 +42,7 @@ export default struct AddPersonDialog { | ||
| 40 | .onClick(async () => { | 42 | .onClick(async () => { |
| 41 | const res: AxiosResponse<beanType> = await companyAdd(this.addForm) | 43 | const res: AxiosResponse<beanType> = await companyAdd(this.addForm) |
| 42 | promptAction.showToast({message: res.data.msg}) | 44 | promptAction.showToast({message: res.data.msg}) |
| 45 | + this.onChange() | ||
| 43 | this.controller.close() | 46 | this.controller.close() |
| 44 | }) | 47 | }) |
| 45 | } | 48 | } |
| @@ -14,7 +14,7 @@ import { PrintBiddingTokenUtils } from '../mediation_adtype/test/PrintBiddintTok | @@ -14,7 +14,7 @@ import { PrintBiddingTokenUtils } from '../mediation_adtype/test/PrintBiddintTok | ||
| 14 | import { window, promptAction, router } from '@kit.ArkUI' | 14 | import { window, promptAction, router } from '@kit.ArkUI' |
| 15 | import { DemoConstants } from '../entryability/DemoConstants' | 15 | import { DemoConstants } from '../entryability/DemoConstants' |
| 16 | 16 | ||
| 17 | -import('./SplashAdShowPage') | 17 | +import('./CreateCamera') |
| 18 | 18 | ||
| 19 | @Builder | 19 | @Builder |
| 20 | function bottomViewBuilder() { | 20 | function bottomViewBuilder() { |
| @@ -111,7 +111,13 @@ export struct SplashAdDemoPage { | @@ -111,7 +111,13 @@ export struct SplashAdDemoPage { | ||
| 111 | 111 | ||
| 112 | build() { | 112 | build() { |
| 113 | Column() { | 113 | Column() { |
| 114 | + Stack(){ | ||
| 115 | + Progress({ value: 0, total: 10, type: ProgressType.Ring }) | ||
| 116 | + .width(120).color('#409EFF').backgroundColor('#fff') | ||
| 117 | + .style({ strokeWidth: 10, status: ProgressStatus.LOADING }) | ||
| 118 | + | ||
| 114 | Image($r('app.media.logo')).width(60).height(60) | 119 | Image($r('app.media.logo')).width(60).height(60) |
| 120 | + } | ||
| 115 | }.width('100%').height('100%').justifyContent(FlexAlign.Center) | 121 | }.width('100%').height('100%').justifyContent(FlexAlign.Center) |
| 116 | } | 122 | } |
| 117 | 123 |
| @@ -496,9 +496,6 @@ struct EditUser { | @@ -496,9 +496,6 @@ struct EditUser { | ||
| 496 | } | 496 | } |
| 497 | 497 | ||
| 498 | pageTransition() { | 498 | pageTransition() { |
| 499 | - // 该页面进入动画时长为1000ms,尽量与另一页面的退出动画时长匹配 | ||
| 500 | - PageTransitionEnter({ duration: 500 }) | ||
| 501 | - .slide(SlideEffect.Left).opacity(0) | ||
| 502 | // 该页面退出动画时长为1200ms,尽量与另一页面的进入动画时长匹配 | 499 | // 该页面退出动画时长为1200ms,尽量与另一页面的进入动画时长匹配 |
| 503 | PageTransitionExit({ duration: 500 }) | 500 | PageTransitionExit({ duration: 500 }) |
| 504 | .translate({ x: 150.0 }) | 501 | .translate({ x: 150.0 }) |
entry/src/main/ets/pages/CreateCamera.ets
0 → 100644
| 1 | +import camera from '@ohos.multimedia.camera'; | ||
| 2 | +import media from '@ohos.multimedia.media'; | ||
| 3 | +import { BusinessError } from '@ohos.base'; | ||
| 4 | +import { promptAction, router } from '@kit.ArkUI' | ||
| 5 | +import { common } from '@kit.AbilityKit'; | ||
| 6 | +import { FileUtil, CommonConstants } from '../utils/FileUtil'; | ||
| 7 | +import { uploadFileByTask } from '../utils/uploadCloud' | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 视频录制 | ||
| 11 | + */ | ||
| 12 | + | ||
| 13 | +interface routerParams { | ||
| 14 | + cosKeyStr: string; | ||
| 15 | + relateId: number; | ||
| 16 | +} | ||
| 17 | + | ||
| 18 | +const TAG: string = 'Record'; | ||
| 19 | +let context = getContext(this) as common.UIAbilityContext; | ||
| 20 | +let routerParamsData: routerParams = router.getParams() as routerParams; | ||
| 21 | +@Entry | ||
| 22 | +@Component | ||
| 23 | +struct CreateCamera { | ||
| 24 | + @State xComponentWidth: number = 0; | ||
| 25 | + @State xComponentHeight: number = 0; | ||
| 26 | + @State recording: boolean = false; | ||
| 27 | + @State path: string = ''; | ||
| 28 | + @State countTime: number = 0; | ||
| 29 | + @State cameraManager: camera.CameraManager | undefined = undefined; | ||
| 30 | + @State videoOutput: camera.VideoOutput | undefined = undefined; | ||
| 31 | + @State captureSession: camera.Session | undefined = undefined; | ||
| 32 | + @State cameraInput: camera.CameraInput | undefined = undefined; | ||
| 33 | + @State previewOutput: camera.PreviewOutput | undefined = undefined; | ||
| 34 | + @State avRecorder: media.AVRecorder | undefined = undefined; | ||
| 35 | + private mXComponentController: XComponentController = new XComponentController; | ||
| 36 | + private surfaceId: string = ''; | ||
| 37 | + url: string = ''; | ||
| 38 | + timer: number = 0; | ||
| 39 | + | ||
| 40 | + aboutToAppear() { | ||
| 41 | + // 创建存放视频文件 | ||
| 42 | + this.path = context.filesDir + '/' + 'VIDEO_' + Date.parse(new Date().toString()) + '.mp4'; | ||
| 43 | + let file = FileUtil.createOrOpen(this.path); | ||
| 44 | + this.url = 'fd://' + file.fd; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + build() { | ||
| 48 | + Stack({ alignContent: Alignment.Top }) { | ||
| 49 | + XComponent({ | ||
| 50 | + id: 'componentId', | ||
| 51 | + type: XComponentType.SURFACE, | ||
| 52 | + controller: this.mXComponentController, | ||
| 53 | + }) | ||
| 54 | + .onLoad(async () => { | ||
| 55 | + this.surfaceId = this.mXComponentController.getXComponentSurfaceId(); | ||
| 56 | + await this.initCamera(getContext(this), this.surfaceId); | ||
| 57 | + }) | ||
| 58 | + .height(CommonConstants.SEVENTY_PERCENT) | ||
| 59 | + .margin({ | ||
| 60 | + top: CommonConstants.FIFTEEN_PERCENT | ||
| 61 | + }) | ||
| 62 | + Column() { | ||
| 63 | + Text(`录制时长:${this.countTime}s`).fontSize(16).fontColor(Color.White) | ||
| 64 | + Blank() | ||
| 65 | + Row() { | ||
| 66 | + Image(this.recording ? $r('app.media.camera_pause_video_4x') : $r('app.media.camera_take_video_4x')) | ||
| 67 | + .width(px2vp(CommonConstants.IMAGE_SIZE)) | ||
| 68 | + .height(px2vp(CommonConstants.IMAGE_SIZE)) | ||
| 69 | + .onClick(async () => { | ||
| 70 | + if (this.recording) { | ||
| 71 | + clearInterval(this.timer); | ||
| 72 | + this.timer = 0 | ||
| 73 | + await this.stopRecord(); | ||
| 74 | + await uploadFileByTask(routerParamsData.cosKeyStr, routerParamsData.relateId, this.path); | ||
| 75 | + router.back() | ||
| 76 | + } else { | ||
| 77 | + this.timer = setInterval(async () => { | ||
| 78 | + this.countTime++; | ||
| 79 | + if(this.countTime >= 120){ | ||
| 80 | + clearInterval(this.timer); | ||
| 81 | + this.timer = 0 | ||
| 82 | + await this.stopRecord(); | ||
| 83 | + await uploadFileByTask(routerParamsData.cosKeyStr, routerParamsData.relateId, this.path); | ||
| 84 | + router.back() | ||
| 85 | + } | ||
| 86 | + }, 1000); | ||
| 87 | + this.startRecord(); | ||
| 88 | + } | ||
| 89 | + this.recording = !this.recording; | ||
| 90 | + }) | ||
| 91 | + } | ||
| 92 | + .width(CommonConstants.FULL_PERCENT) | ||
| 93 | + .height(120) | ||
| 94 | + .margin({ bottom: 60 }) | ||
| 95 | + .justifyContent(FlexAlign.Center) | ||
| 96 | + .alignItems(VerticalAlign.Center) | ||
| 97 | + } | ||
| 98 | + .width(CommonConstants.FULL_PERCENT) | ||
| 99 | + .height(CommonConstants.FULL_PERCENT) | ||
| 100 | + .justifyContent(FlexAlign.Start) | ||
| 101 | + .alignItems(HorizontalAlign.Start) | ||
| 102 | + } | ||
| 103 | + .backgroundColor(Color.Black) | ||
| 104 | + .width(CommonConstants.FULL_PERCENT) | ||
| 105 | + .height(CommonConstants.FULL_PERCENT) | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + // 初始化相机 | ||
| 109 | + async initCamera(context: common.Context, surfaceId: string) { | ||
| 110 | + this.cameraManager = camera.getCameraManager(context); | ||
| 111 | + if (!this.cameraManager) { | ||
| 112 | + promptAction.showToast({ message: 'camera.getCameraManager error' }) | ||
| 113 | + return; | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + this.cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => { | ||
| 117 | + promptAction.showToast({ message: `camera : ${cameraStatusInfo.camera.cameraId},status: ${cameraStatusInfo.status}` }) | ||
| 118 | + }); | ||
| 119 | + | ||
| 120 | + let cameraArray: Array<camera.CameraDevice> = []; | ||
| 121 | + try { | ||
| 122 | + cameraArray = this.cameraManager.getSupportedCameras(); | ||
| 123 | + } catch (error) { | ||
| 124 | + let err = error as BusinessError; | ||
| 125 | + promptAction.showToast({ message: `getSupportedCameras call failed. error code: ${err.code}` }) | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + if (cameraArray.length <= 0) { | ||
| 129 | + promptAction.showToast({ message: 'cameraManager.getSupportedCameras error' }) | ||
| 130 | + return; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + let cameraOutputCap: camera.CameraOutputCapability = | ||
| 134 | + this.cameraManager.getSupportedOutputCapability(cameraArray[0], camera.SceneMode.NORMAL_VIDEO); | ||
| 135 | + if (!cameraOutputCap) { | ||
| 136 | + promptAction.showToast({ message: 'cameraManager.getSupportedOutputCapability error' }) | ||
| 137 | + return; | ||
| 138 | + } | ||
| 139 | + promptAction.showToast({ message: 'outputCapability: ' + JSON.stringify(cameraOutputCap) }) | ||
| 140 | + | ||
| 141 | + let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles; | ||
| 142 | + if (!previewProfilesArray) { | ||
| 143 | + promptAction.showToast({ message: 'createOutput previewProfilesArray === null || undefined' }) | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles; | ||
| 147 | + if (!photoProfilesArray) { | ||
| 148 | + promptAction.showToast({ message: 'createOutput photoProfilesArray === null || undefined' }) | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + let videoProfilesArray: Array<camera.VideoProfile> = cameraOutputCap.videoProfiles; | ||
| 152 | + if (!videoProfilesArray) { | ||
| 153 | + promptAction.showToast({ message: 'createOutput videoProfilesArray === null || undefined' }) | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + let videoSize: camera.Size = { | ||
| 157 | + width: 640, | ||
| 158 | + height: 480 | ||
| 159 | + } | ||
| 160 | + let videoProfile: undefined | camera.VideoProfile = videoProfilesArray.find((profile: camera.VideoProfile) => { | ||
| 161 | + return profile.size.width === videoSize.width && profile.size.height === videoSize.height; | ||
| 162 | + }); | ||
| 163 | + | ||
| 164 | + if (!videoProfile) { | ||
| 165 | + promptAction.showToast({ message: 'videoProfile is not found' }) | ||
| 166 | + return; | ||
| 167 | + } | ||
| 168 | + | ||
| 169 | + let aVRecorderProfile: media.AVRecorderProfile = { | ||
| 170 | + audioBitrate: 48000, | ||
| 171 | + audioChannels: 2, | ||
| 172 | + audioCodec: media.CodecMimeType.AUDIO_AAC, | ||
| 173 | + audioSampleRate: 48000, | ||
| 174 | + fileFormat: media.ContainerFormatType.CFT_MPEG_4, | ||
| 175 | + videoBitrate: 2000000, | ||
| 176 | + videoCodec: media.CodecMimeType.VIDEO_AVC, | ||
| 177 | + videoFrameWidth: videoSize.width, | ||
| 178 | + videoFrameHeight: videoSize.height, | ||
| 179 | + videoFrameRate: 30 | ||
| 180 | + }; | ||
| 181 | + | ||
| 182 | + let aVRecorderConfig: media.AVRecorderConfig = { | ||
| 183 | + audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, | ||
| 184 | + videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, | ||
| 185 | + profile: aVRecorderProfile, | ||
| 186 | + url: this.url, | ||
| 187 | + rotation: 0, | ||
| 188 | + location: { | ||
| 189 | + latitude: 30, | ||
| 190 | + longitude: 130 | ||
| 191 | + } | ||
| 192 | + }; | ||
| 193 | + | ||
| 194 | + try { | ||
| 195 | + this.avRecorder = await media.createAVRecorder(); | ||
| 196 | + } catch (error) { | ||
| 197 | + let err = error as BusinessError; | ||
| 198 | + promptAction.showToast({ message: `createAVRecorder call failed. error code: ${err.code}` }) | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + if (this.avRecorder === undefined) { | ||
| 202 | + return; | ||
| 203 | + } | ||
| 204 | + | ||
| 205 | + try { | ||
| 206 | + await this.avRecorder.prepare(aVRecorderConfig); | ||
| 207 | + } catch (error) { | ||
| 208 | + let err = error as BusinessError; | ||
| 209 | + promptAction.showToast({ message: `prepare call failed. error code: ${err.code}` }) | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + let videoSurfaceId: string | undefined = undefined; | ||
| 213 | + try { | ||
| 214 | + videoSurfaceId = await this.avRecorder.getInputSurface(); | ||
| 215 | + } catch (error) { | ||
| 216 | + let err = error as BusinessError; | ||
| 217 | + promptAction.showToast({ message: `getInputSurface call failed. error code: ${err.code}` }) | ||
| 218 | + } | ||
| 219 | + if (videoSurfaceId === undefined) { | ||
| 220 | + return; | ||
| 221 | + } | ||
| 222 | + | ||
| 223 | + try { | ||
| 224 | + this.videoOutput = this.cameraManager.createVideoOutput(videoProfile, videoSurfaceId); | ||
| 225 | + } catch (error) { | ||
| 226 | + let err = error as BusinessError; | ||
| 227 | + promptAction.showToast({ message: `Failed to create the videoOutput instance. error: ${JSON.stringify(err)}` }) | ||
| 228 | + } | ||
| 229 | + if (this.videoOutput === undefined) { | ||
| 230 | + return; | ||
| 231 | + } | ||
| 232 | + this.videoOutput.on('frameStart', () => { | ||
| 233 | + promptAction.showToast({ message: 'Video frame started' }) | ||
| 234 | + }); | ||
| 235 | + | ||
| 236 | + this.videoOutput.on('error', (error: BusinessError) => { | ||
| 237 | + promptAction.showToast({ message: `Video frame error code: ${error.code}` }) | ||
| 238 | + }); | ||
| 239 | + | ||
| 240 | + try { | ||
| 241 | + this.captureSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO) as camera.VideoSession; | ||
| 242 | + ; | ||
| 243 | + } catch (error) { | ||
| 244 | + let err = error as BusinessError; | ||
| 245 | + promptAction.showToast({ message: `Failed to create the CaptureSession instance. errorCode = ${err.code}` }) | ||
| 246 | + } | ||
| 247 | + if (this.captureSession === undefined) { | ||
| 248 | + return; | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + try { | ||
| 252 | + this.captureSession.beginConfig(); | ||
| 253 | + } catch (error) { | ||
| 254 | + let err = error as BusinessError; | ||
| 255 | + promptAction.showToast({ message: `Failed to beginConfig. errorCode = ${err.code}` }) | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + let cameraInput: camera.CameraInput | undefined = undefined; | ||
| 259 | + try { | ||
| 260 | + cameraInput = this.cameraManager.createCameraInput(cameraArray[0]); | ||
| 261 | + } catch (error) { | ||
| 262 | + let err = error as BusinessError; | ||
| 263 | + promptAction.showToast({ message: `Failed to createCameraInput. errorCode = ${err.code}` }) | ||
| 264 | + } | ||
| 265 | + if (cameraInput === undefined) { | ||
| 266 | + return; | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + let cameraDevice: camera.CameraDevice = cameraArray[0]; | ||
| 270 | + cameraInput.on('error', cameraDevice, (error: BusinessError) => { | ||
| 271 | + promptAction.showToast({ message: `Camera input error code: ${error.code}` }) | ||
| 272 | + }); | ||
| 273 | + | ||
| 274 | + try { | ||
| 275 | + await cameraInput.open(); | ||
| 276 | + } catch (error) { | ||
| 277 | + let err = error as BusinessError; | ||
| 278 | + promptAction.showToast({ message: `Failed to open cameraInput. errorCode = ${err.code}` }) | ||
| 279 | + } | ||
| 280 | + | ||
| 281 | + try { | ||
| 282 | + this.captureSession.addInput(cameraInput); | ||
| 283 | + } catch (error) { | ||
| 284 | + let err = error as BusinessError; | ||
| 285 | + promptAction.showToast({ message: `Failed to add cameraInput. errorCode = ${err.code}` }) | ||
| 286 | + } | ||
| 287 | + | ||
| 288 | + let previewOutput: camera.PreviewOutput | undefined = undefined; | ||
| 289 | + try { | ||
| 290 | + previewOutput = this.cameraManager.createPreviewOutput(videoProfile, surfaceId); | ||
| 291 | + } catch (error) { | ||
| 292 | + let err = error as BusinessError; | ||
| 293 | + promptAction.showToast({ message: `Failed to create the previewOutput instance. error: ${JSON.stringify(err)}` }) | ||
| 294 | + } | ||
| 295 | + | ||
| 296 | + if (previewOutput === undefined) { | ||
| 297 | + return; | ||
| 298 | + } | ||
| 299 | + | ||
| 300 | + try { | ||
| 301 | + this.captureSession.addOutput(previewOutput); | ||
| 302 | + } catch (error) { | ||
| 303 | + let err = error as BusinessError; | ||
| 304 | + promptAction.showToast({ message: `Failed to add previewOutput. errorCode = ${err.code}` }) | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + try { | ||
| 308 | + this.captureSession.addOutput(this.videoOutput); | ||
| 309 | + } catch (error) { | ||
| 310 | + let err = error as BusinessError; | ||
| 311 | + promptAction.showToast({ message: `Failed to add videoOutput. errorCode = ${err.code}` }) | ||
| 312 | + } | ||
| 313 | + | ||
| 314 | + try { | ||
| 315 | + await this.captureSession.commitConfig(); | ||
| 316 | + } catch (error) { | ||
| 317 | + let err = error as BusinessError; | ||
| 318 | + promptAction.showToast({ message: `Failed to commitConfig. errorCode = ${err.code}` }) | ||
| 319 | + } | ||
| 320 | + | ||
| 321 | + try { | ||
| 322 | + await this.captureSession.start(); | ||
| 323 | + } catch (error) { | ||
| 324 | + let err = error as BusinessError; | ||
| 325 | + promptAction.showToast({ message: `Failed to start captureSession. errorCode = ${err.code}` }) | ||
| 326 | + } | ||
| 327 | + | ||
| 328 | + this.videoOutput.start((err: BusinessError) => { | ||
| 329 | + if (err) { | ||
| 330 | + promptAction.showToast({ message: `Failed to start the video output. error: ${JSON.stringify(err)}` }) | ||
| 331 | + return; | ||
| 332 | + } | ||
| 333 | + promptAction.showToast({message: 'Callback invoked to indicate the video output start success.'}) | ||
| 334 | + }); | ||
| 335 | + } | ||
| 336 | + | ||
| 337 | + // 开始录像 | ||
| 338 | + async startRecord() { | ||
| 339 | + if (this.avRecorder) { | ||
| 340 | + try { | ||
| 341 | + await this.avRecorder.start(); | ||
| 342 | + } catch (error) { | ||
| 343 | + let err = error as BusinessError; | ||
| 344 | + promptAction.showToast({ message: `avRecorder start error: ${JSON.stringify(err)}` }) | ||
| 345 | + } | ||
| 346 | + } | ||
| 347 | + } | ||
| 348 | + | ||
| 349 | + // 停止录像 | ||
| 350 | + async stopRecord() { | ||
| 351 | + if (this.avRecorder) { | ||
| 352 | + try { | ||
| 353 | + if (this.videoOutput) { | ||
| 354 | + this.videoOutput.stop((err: BusinessError) => { | ||
| 355 | + if (err) { | ||
| 356 | + promptAction.showToast({ message: `Failed to stop the video output. error: ${JSON.stringify(err)}` }) | ||
| 357 | + return; | ||
| 358 | + } | ||
| 359 | + promptAction.showToast({message: 'Callback invoked to indicate the video output stop success.'}) | ||
| 360 | + }); | ||
| 361 | + } | ||
| 362 | + try { | ||
| 363 | + await this.avRecorder.stop(); | ||
| 364 | + await this.avRecorder.release(); | ||
| 365 | + } catch (error) { | ||
| 366 | + let err = error as BusinessError; | ||
| 367 | + promptAction.showToast({ message: `avRecorder stop error: ${JSON.stringify(err)}` }) | ||
| 368 | + } | ||
| 369 | + } catch (error) { | ||
| 370 | + let err = error as BusinessError; | ||
| 371 | + promptAction.showToast({ message: `avRecorder stop error: ${JSON.stringify(err)}` }) | ||
| 372 | + } | ||
| 373 | + try { | ||
| 374 | + if (this.captureSession) { | ||
| 375 | + this.captureSession.stop(); | ||
| 376 | + } | ||
| 377 | + if (this.cameraInput) { | ||
| 378 | + this.cameraInput.close(); | ||
| 379 | + } | ||
| 380 | + if (this.previewOutput) { | ||
| 381 | + this.previewOutput.release(); | ||
| 382 | + } | ||
| 383 | + if (this.videoOutput) { | ||
| 384 | + this.videoOutput.release(); | ||
| 385 | + } | ||
| 386 | + if (this.captureSession) { | ||
| 387 | + this.captureSession.release(); | ||
| 388 | + } | ||
| 389 | + if (this.captureSession) { | ||
| 390 | + this.captureSession = undefined; | ||
| 391 | + } | ||
| 392 | + } catch (error) { | ||
| 393 | + let err = error as BusinessError; | ||
| 394 | + promptAction.showToast({ message: `avRecorder stop error: ${JSON.stringify(err)}` }) | ||
| 395 | + } | ||
| 396 | + } | ||
| 397 | + } | ||
| 398 | +} |
| @@ -3,19 +3,20 @@ import { pasteboard } from '@kit.BasicServicesKit'; | @@ -3,19 +3,20 @@ import { pasteboard } from '@kit.BasicServicesKit'; | ||
| 3 | import preferencesUtils from '../utils/preferences' | 3 | import preferencesUtils from '../utils/preferences' |
| 4 | import { AxiosResponse } from '@ohos/axios' | 4 | import { AxiosResponse } from '@ohos/axios' |
| 5 | import { HmParseHTML } from "@wuyan/html_parse" | 5 | import { HmParseHTML } from "@wuyan/html_parse" |
| 6 | -import { BusinessError } from '@kit.BasicServicesKit'; | ||
| 7 | -import { uploadFileByTask, selectImgOrVideo } from '../utils/uploadCloud' | ||
| 8 | import { basePath } from '../utils/baseUrl' | 6 | import { basePath } from '../utils/baseUrl' |
| 9 | import {getCloudDown, beanType} from '../api/user' | 7 | import {getCloudDown, beanType} from '../api/user' |
| 10 | import loadingDialog from '../dialog/LoadingDialog' | 8 | import loadingDialog from '../dialog/LoadingDialog' |
| 11 | import UploadTipDialog from '../dialog/UploadTipDialog' | 9 | import UploadTipDialog from '../dialog/UploadTipDialog' |
| 12 | import { getReportDetail, getMalfunctionList, deleteRecords, successReport, returnSing } from '../api/originalRecords' | 10 | import { getReportDetail, getMalfunctionList, deleteRecords, successReport, returnSing } from '../api/originalRecords' |
| 13 | -import { reportDetailTest, reportDetailData, ProjectList, MalfunctionListTest, MalfunctionListRow, configTest } from '../api/recordsType' | 11 | +import { reportDetailTest, reportDetailData, ProjectList, ItemList, MalfunctionListTest, MalfunctionListRow, configTest } from '../api/recordsType' |
| 14 | import { pushOutsideWeb } from '../utils/pushOutsideWeb' | 12 | import { pushOutsideWeb } from '../utils/pushOutsideWeb' |
| 15 | import ThemeStaticTest from '../components/ThemeStaticText' | 13 | import ThemeStaticTest from '../components/ThemeStaticText' |
| 16 | import NavHeader from '../components/NavHeader' | 14 | import NavHeader from '../components/NavHeader' |
| 17 | 15 | ||
| 18 | - | 16 | +interface showVideoOrImg { |
| 17 | + cosKey: string | null; | ||
| 18 | + itemName: string; | ||
| 19 | +} | ||
| 19 | interface routerParams { | 20 | interface routerParams { |
| 20 | reportId: number | 21 | reportId: number |
| 21 | } | 22 | } |
| @@ -86,6 +87,10 @@ struct DetailRecords { | @@ -86,6 +87,10 @@ struct DetailRecords { | ||
| 86 | }) | 87 | }) |
| 87 | } | 88 | } |
| 88 | 89 | ||
| 90 | + // 判断是否存在视频或图片 | ||
| 91 | + isImgOrVideo = (list: ItemList[]): boolean => { | ||
| 92 | + return list.some(item => item.cosKey !== null) | ||
| 93 | + } | ||
| 89 | build() { | 94 | build() { |
| 90 | Column(){ | 95 | Column(){ |
| 91 | NavHeader({title: '维保记录详情'}) | 96 | NavHeader({title: '维保记录详情'}) |
| @@ -235,20 +240,33 @@ struct DetailRecords { | @@ -235,20 +240,33 @@ struct DetailRecords { | ||
| 235 | Column({space: 5}){ | 240 | Column({space: 5}){ |
| 236 | Row(){ | 241 | Row(){ |
| 237 | Row({space: 5}){ | 242 | Row({space: 5}){ |
| 238 | - Text((index + 1).toString()).padding(10).borderRadius(5) | ||
| 239 | - .backgroundColor(Color.Gray).fontSize('#666') | ||
| 240 | - Text(item.projectName).fontSize(12).fontColor('#999') | 243 | + Text((index + 1).toString()).width(40).height(40).borderRadius(5) |
| 244 | + .backgroundColor('#eee').fontSize('#666').textAlign(TextAlign.Center) | ||
| 245 | + Row(){ | ||
| 246 | + Text(item.projectName).fontSize(16).fontColor('#1890ff') | ||
| 247 | + Image($r('app.media.edit_1')).width(16).margin({right: 4}) | ||
| 248 | + }.onClick(() => { | ||
| 249 | + router.pushUrl({ | ||
| 250 | + url: 'pages/FireProtectionDetail', | ||
| 251 | + params: item | ||
| 252 | + }) | ||
| 253 | + }) | ||
| 241 | } | 254 | } |
| 242 | Row(){ | 255 | Row(){ |
| 243 | Text('查看视频/图片内容').fontSize(12).fontColor('#1890ff') | 256 | Text('查看视频/图片内容').fontSize(12).fontColor('#1890ff') |
| 244 | Image($r('app.media.right_arrow')).width(12) | 257 | Image($r('app.media.right_arrow')).width(12) |
| 245 | - }.visibility(this.isShowCloudDown && item.cosKey !== null ? Visibility.Visible : Visibility.None) | 258 | + }.visibility(this.isImgOrVideo(item.itemList) ? Visibility.Visible : Visibility.None) |
| 246 | .onClick(() => { | 259 | .onClick(() => { |
| 260 | + const newArr: showVideoOrImg[] = item.itemList.map((item: ItemList): showVideoOrImg => { | ||
| 261 | + return { | ||
| 262 | + cosKey: item.cosKey, | ||
| 263 | + itemName: item.itemName | ||
| 264 | + } | ||
| 265 | + }) | ||
| 247 | router.pushUrl({ | 266 | router.pushUrl({ |
| 248 | url: 'pages/VideoDetail', | 267 | url: 'pages/VideoDetail', |
| 249 | params: { | 268 | params: { |
| 250 | - cosKey: item.cosKey, | ||
| 251 | - relateId: item.relateId | 269 | + cosKeyList: newArr |
| 252 | } | 270 | } |
| 253 | }) | 271 | }) |
| 254 | }) | 272 | }) |
| @@ -260,37 +278,6 @@ struct DetailRecords { | @@ -260,37 +278,6 @@ struct DetailRecords { | ||
| 260 | .borderWidth(1).fontSize(12).borderRadius(4).lineHeight(16).fontColor(item.state == '0' ? '#ff4949' : '#13ce66') | 278 | .borderWidth(1).fontSize(12).borderRadius(4).lineHeight(16).fontColor(item.state == '0' ? '#ff4949' : '#13ce66') |
| 261 | .backgroundColor(item.state == '0' ? '#ffeded' : '#e7faf0').borderColor(item.state == '0' ? '#ffdbdb' : '#d0f5e0') | 279 | .backgroundColor(item.state == '0' ? '#ffeded' : '#e7faf0').borderColor(item.state == '0' ? '#ffdbdb' : '#d0f5e0') |
| 262 | }.width('100%').justifyContent(FlexAlign.SpaceBetween) | 280 | }.width('100%').justifyContent(FlexAlign.SpaceBetween) |
| 263 | - Row(){ | ||
| 264 | - Row(){ | ||
| 265 | - Image($r('app.media.photo')).width(12).margin({right: 4}) | ||
| 266 | - Text('上传视频/图片').fontSize(12).fontColor('#1890ff') | ||
| 267 | - }.layoutWeight(1).justifyContent(FlexAlign.Center) | ||
| 268 | - .visibility(this.isShowCloudDown ? Visibility.Visible : Visibility.None) | ||
| 269 | - .onClick(async () => { | ||
| 270 | - // 上传文件到腾讯云存储 | ||
| 271 | - try { | ||
| 272 | - let key: string = item.cosKey == null ? '' : item.cosKey | ||
| 273 | - let systemPhotoImagePath: string = await selectImgOrVideo() // 选择文件 | ||
| 274 | - this.loadingController.open() | ||
| 275 | - await uploadFileByTask(key, item.relateId, systemPhotoImagePath) | ||
| 276 | - this.loadingController.close() | ||
| 277 | - } catch (error) { | ||
| 278 | - let err: BusinessError = error as BusinessError; | ||
| 279 | - console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`); | ||
| 280 | - } | ||
| 281 | - }) | ||
| 282 | - Text().width(2).height(16).backgroundColor('#eee').visibility(this.isShowCloudDown ? Visibility.Visible : Visibility.None) | ||
| 283 | - Row(){ | ||
| 284 | - Image($r('app.media.edit_1')).width(12).margin({right: 4}) | ||
| 285 | - Text('编辑详情').fontSize(12).fontColor('#1890ff').onClick(() => { | ||
| 286 | - router.pushUrl({ | ||
| 287 | - url: 'pages/FireProtectionDetail', | ||
| 288 | - params: item | ||
| 289 | - }) | ||
| 290 | - }) | ||
| 291 | - }.layoutWeight(1).justifyContent(FlexAlign.Center) | ||
| 292 | - }.width('100%').padding({top: 5}).border({width: {top: 1}, color: '#eee'}) | ||
| 293 | - .visibility(item.state == '0' ? Visibility.Visible : Visibility.None) | ||
| 294 | }.padding({top: 10, left: 10, right: 10, bottom: 10}).borderWidth(1).borderColor('#eee').shadow({ radius: 5, color: Color.Gray }).borderRadius(5) | 281 | }.padding({top: 10, left: 10, right: 10, bottom: 10}).borderWidth(1).borderColor('#eee').shadow({ radius: 5, color: Color.Gray }).borderRadius(5) |
| 295 | }) | 282 | }) |
| 296 | }.backgroundColor('#fff').borderRadius(10).padding(10).width('100%') | 283 | }.backgroundColor('#fff').borderRadius(10).padding(10).width('100%') |
| @@ -500,9 +487,6 @@ struct DetailRecords { | @@ -500,9 +487,6 @@ struct DetailRecords { | ||
| 500 | 487 | ||
| 501 | 488 | ||
| 502 | pageTransition() { | 489 | pageTransition() { |
| 503 | - // 该页面进入动画时长为1000ms,尽量与另一页面的退出动画时长匹配 | ||
| 504 | - PageTransitionEnter({ duration: 500 }) | ||
| 505 | - .slide(SlideEffect.Left).opacity(0) | ||
| 506 | // 该页面退出动画时长为1200ms,尽量与另一页面的进入动画时长匹配 | 490 | // 该页面退出动画时长为1200ms,尽量与另一页面的进入动画时长匹配 |
| 507 | PageTransitionExit({ duration: 500 }) | 491 | PageTransitionExit({ duration: 500 }) |
| 508 | .translate({ x: 150.0 }) | 492 | .translate({ x: 150.0 }) |
| 1 | -import { router } from '@kit.ArkUI' | 1 | +import { router, promptAction } from '@kit.ArkUI' |
| 2 | import { ProjectList } from '../api/recordsType' | 2 | import { ProjectList } from '../api/recordsType' |
| 3 | import { webview } from '@kit.ArkWeb' | 3 | import { webview } from '@kit.ArkWeb' |
| 4 | import { basePath } from '../utils/baseUrl' | 4 | import { basePath } from '../utils/baseUrl' |
| 5 | +import fs from '@ohos.file.fs'; | ||
| 5 | import preferencesUtils from '../utils/preferences' | 6 | import preferencesUtils from '../utils/preferences' |
| 7 | +import { BusinessError, request } from '@kit.BasicServicesKit'; | ||
| 8 | +import { cameraPickerImg, cameraPickerVideo, videoCompressMethod } from '../utils/uploadFile' | ||
| 9 | +import { getCosKey, cosKeyTest, cosKeyData, uploadVideoOrImg } from '../api/cosKey' | ||
| 10 | +import loadingDialog from '../dialog/LoadingDialog' | ||
| 11 | +import { rpc } from '@kit.IPCKit'; | ||
| 12 | +import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit'; | ||
| 13 | +import { AxiosResponse } from '@ohos/axios' | ||
| 14 | + | ||
| 6 | let routerInfo: ProjectList = router.getParams() as ProjectList | 15 | let routerInfo: ProjectList = router.getParams() as ProjectList |
| 16 | +const context = getContext() as common.UIAbilityContext; | ||
| 7 | 17 | ||
| 8 | @Entry | 18 | @Entry |
| 9 | @Component | 19 | @Component |
| @@ -11,13 +21,161 @@ struct FireProtectionDetail { | @@ -11,13 +21,161 @@ struct FireProtectionDetail { | ||
| 11 | controller: RichEditorController = new RichEditorController(); | 21 | controller: RichEditorController = new RichEditorController(); |
| 12 | options: RichEditorOptions = { controller: this.controller }; | 22 | options: RichEditorOptions = { controller: this.controller }; |
| 13 | @State projectInfo: ProjectList = routerInfo | 23 | @State projectInfo: ProjectList = routerInfo |
| 24 | + private result: boolean = false; | ||
| 25 | + permissions: Array<Permissions> = [ | ||
| 26 | + 'ohos.permission.CAMERA', | ||
| 27 | + 'ohos.permission.MICROPHONE', | ||
| 28 | + 'ohos.permission.MEDIA_LOCATION' | ||
| 29 | + ]; | ||
| 14 | webviewController: webview.WebviewController = new webview.WebviewController() | 30 | webviewController: webview.WebviewController = new webview.WebviewController() |
| 31 | + | ||
| 32 | + aboutToAppear(): void { | ||
| 33 | + this.reqPermissionsFromUser(this.permissions, context) | ||
| 34 | + } | ||
| 35 | + // 加载弹窗 | ||
| 36 | + loadingController: CustomDialogController = new CustomDialogController({ | ||
| 37 | + builder: loadingDialog(), | ||
| 38 | + customStyle: true, | ||
| 39 | + offset: { dx: 0, dy: 0 }, | ||
| 40 | + alignment: DialogAlignment.Center, | ||
| 41 | + autoCancel: false | ||
| 42 | + }) | ||
| 43 | + | ||
| 44 | + // 获取用户授权 | ||
| 45 | + reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext) { | ||
| 46 | + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); | ||
| 47 | + atManager.requestPermissionsFromUser(context, permissions).then((data) => { | ||
| 48 | + let grantStatus: Array<number> = data.authResults; | ||
| 49 | + let length: number = grantStatus.length; | ||
| 50 | + for (let i = 0; i < length; i++) { | ||
| 51 | + if (grantStatus[i] === 0) { | ||
| 52 | + promptAction.showToast({message: 'User authorized.'}) | ||
| 53 | + } else { | ||
| 54 | + promptAction.showToast({message: 'User denied authorization.'}) | ||
| 55 | + return; | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + }).catch((err: BusinessError) => { | ||
| 59 | + promptAction.showToast({message: `Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`}) | ||
| 60 | + }) | ||
| 61 | + } | ||
| 62 | + // 检查用户是否授权 | ||
| 63 | + checkAccessToken(permissions: Array<Permissions>) { | ||
| 64 | + // Determine the authorization status. | ||
| 65 | + let callerTokenId: number = rpc.IPCSkeleton.getCallingTokenId(); | ||
| 66 | + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); | ||
| 67 | + try { | ||
| 68 | + for (let i = 0; i < permissions.length; i++) { | ||
| 69 | + let data: abilityAccessCtrl.GrantStatus = atManager.verifyAccessTokenSync(callerTokenId, permissions[i]); | ||
| 70 | + if (data === -1) { | ||
| 71 | + this.result = false; | ||
| 72 | + } else { | ||
| 73 | + this.result = true; | ||
| 74 | + } | ||
| 75 | + if (!this.result) { | ||
| 76 | + break; | ||
| 77 | + } | ||
| 78 | + } | ||
| 79 | + } catch (err) { | ||
| 80 | + promptAction.showToast({message: `checkAccessToken catch err->${JSON.stringify(err)}`}) | ||
| 81 | + } | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + // 上传方法 | ||
| 85 | + uploadMethods = async (cosKeyStr: string | null, relateId: number, systemPhotoImagePath: string, fileType: string) => { | ||
| 86 | + let _this = this | ||
| 87 | + _this.loadingController.open() | ||
| 88 | + let cacheDir = getContext().cacheDir // 获取缓存目录 | ||
| 89 | + let filetype = fileType // 设置文件类型 | ||
| 90 | + let filename = Date.now() + '.' + filetype // 设置文件名称 | ||
| 91 | + let fullPath = cacheDir + '/' + filename // 设置文件路径 | ||
| 92 | + const file = fs.openSync(systemPhotoImagePath, fs.OpenMode.READ_ONLY) // 打开文件 | ||
| 93 | + fs.copyFileSync(file.fd, fullPath) // 复制文件 | ||
| 94 | + // 获取直传签名等数据 | ||
| 95 | + let directTransferResult: AxiosResponse<cosKeyTest> = await getCosKey(filename); | ||
| 96 | + let directTransferData: cosKeyData = directTransferResult.data.data | ||
| 97 | + if (directTransferData == null) { | ||
| 98 | + promptAction.showToast({ message: 'getStsDirectSign fail' }); | ||
| 99 | + return; | ||
| 100 | + } | ||
| 101 | + let cosKey = directTransferData.coskey | ||
| 102 | + // 生成上传的url | ||
| 103 | + let url = directTransferData.preSignedUrl | ||
| 104 | + // 开始上传 | ||
| 105 | + try { | ||
| 106 | + let uploadTask = await request.uploadFile(getContext(),{ // 上传图片 | ||
| 107 | + url: url, // 请求地址 | ||
| 108 | + // 请求头 | ||
| 109 | + header:{ | ||
| 110 | + "Content-Type": "application/octet-stream" | ||
| 111 | + }, | ||
| 112 | + method: "PUT", | ||
| 113 | + files:[{ // 上传文件 | ||
| 114 | + filename: filename, // 文件名 | ||
| 115 | + type: 'jpg', // 文件扩展名 | ||
| 116 | + name:'file', // 接口参数名 | ||
| 117 | + uri:`internal://cache/${filename}` // 缓存目录中的要上传给服务器的图片路径 | ||
| 118 | + }], | ||
| 119 | + data:[] | ||
| 120 | + }) | ||
| 121 | + // 上传成功 | ||
| 122 | + uploadTask.on('complete', async (taskStates: Array<request.TaskState>) => { | ||
| 123 | + _this.loadingController.close() | ||
| 124 | + for (let i = 0; i < taskStates.length; i++) { | ||
| 125 | + let cosKeyArr: string[] = [] | ||
| 126 | + if(cosKeyStr !== null) { | ||
| 127 | + cosKeyArr = cosKeyStr.split(';') | ||
| 128 | + } | ||
| 129 | + cosKeyArr.push(cosKey) | ||
| 130 | + console.log('最终的cosKeys数据: ' + cosKeyArr.join(';')) | ||
| 131 | + await uploadVideoOrImg({ cosKey: cosKeyArr.join(';'), relateId: relateId }) | ||
| 132 | + await _this.webviewController.runJavaScript(`window.setKey(${JSON.stringify(cosKeyArr.join(';'))})`) | ||
| 133 | + _this.loadingController.close() | ||
| 134 | + } | ||
| 135 | + }); | ||
| 136 | + // 上传失败 | ||
| 137 | + uploadTask.on('fail', (taskStates: Array<request.TaskState>) => { | ||
| 138 | + _this.loadingController.close() | ||
| 139 | + for (let i = 0; i < taskStates.length; i++) { | ||
| 140 | + promptAction.showToast({ message: '上传失败' }); | ||
| 141 | + _this.loadingController.close() | ||
| 142 | + } | ||
| 143 | + }); | ||
| 144 | + } catch (error) { | ||
| 145 | + let err: BusinessError = error as BusinessError; | ||
| 146 | + console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`); | ||
| 147 | + return error | ||
| 148 | + } | ||
| 149 | + } | ||
| 15 | build() { | 150 | build() { |
| 16 | Column(){ | 151 | Column(){ |
| 17 | Web({ | 152 | Web({ |
| 18 | - src: `${basePath}/report/handle?id=${this.projectInfo.reportId}&pid=${this.projectInfo.projectId}&token=${preferencesUtils.get('XF_TOKEN', '')}`, | 153 | + src: `${basePath}/report/handle?id=${this.projectInfo.reportId}&pid=${this.projectInfo.projectId}&source=harmony&token=${preferencesUtils.get('XF_TOKEN', '')}`, |
| 154 | + // src: 'http://www.xiao-ming.love/', | ||
| 19 | controller: this.webviewController, | 155 | controller: this.webviewController, |
| 20 | }).mixedMode(MixedMode.All).javaScriptAccess(true).domStorageAccess(true) | 156 | }).mixedMode(MixedMode.All).javaScriptAccess(true).domStorageAccess(true) |
| 157 | + .onConsole((event) => { | ||
| 158 | + let data = event.message.getMessage().replace(/^['"]|['"]$/g, ''); | ||
| 159 | + let formatData = data.split('&') | ||
| 160 | + let cosKeyStr: string | null = formatData[1] | ||
| 161 | + let relateId: number = parseInt(formatData[2]) | ||
| 162 | + if (formatData[0] == '鸿蒙图片上传') { | ||
| 163 | + // 使用相机拍照 | ||
| 164 | + cameraPickerImg().then(async systemPhotoImagePath => { | ||
| 165 | + if (systemPhotoImagePath == '' || systemPhotoImagePath == null) { | ||
| 166 | + return promptAction.showToast({ message: '用户取消选择' }); | ||
| 167 | + } | ||
| 168 | + this.uploadMethods(cosKeyStr, relateId, systemPhotoImagePath, 'jpg') | ||
| 169 | + }) | ||
| 170 | + } else if(formatData[0] == '鸿蒙视频上传'){ | ||
| 171 | + // 使用相机录像 | ||
| 172 | + this.checkAccessToken(this.permissions); | ||
| 173 | + if (this.result) { | ||
| 174 | + router.pushUrl({ url: 'pages/CreateCamera', params: { cosKeyStr: cosKeyStr, relateId: relateId} }) | ||
| 175 | + } | ||
| 176 | + } | ||
| 177 | + return false | ||
| 178 | + }) | ||
| 21 | }.height('100%').width('100%') | 179 | }.height('100%').width('100%') |
| 22 | } | 180 | } |
| 23 | } | 181 | } |
| @@ -38,25 +38,26 @@ struct Login { | @@ -38,25 +38,26 @@ struct Login { | ||
| 38 | 38 | ||
| 39 | build() { | 39 | build() { |
| 40 | Column(){ | 40 | Column(){ |
| 41 | - Column({space: 20}){ | ||
| 42 | - Image($r('app.media.logo')).width(100).borderRadius(22) | ||
| 43 | - Text('消防维保助手').fontSize(30).fontWeight(500).fontColor('#fff') | ||
| 44 | - }.margin({top: 50, bottom: 50}) | ||
| 45 | - | ||
| 46 | Column(){ | 41 | Column(){ |
| 42 | + Image($r('app.media.logo')).width(100).borderRadius(22).margin({bottom: 20}) | ||
| 43 | + Text('消防维保助手').fontSize(30).fontWeight(500).fontColor('#fff').margin({bottom: 5}) | ||
| 44 | + Text('鸿蒙专版').fontSize(14).fontColor(Color.White).fontWeight(500) | ||
| 45 | + }.margin({top: 50, bottom: 30}) | ||
| 46 | + | ||
| 47 | + Column({space:10}){ | ||
| 47 | Row(){ | 48 | Row(){ |
| 48 | Image($r('app.media.account')).width(20) | 49 | Image($r('app.media.account')).width(20) |
| 49 | TextInput({text: $$this.loginForm.username, placeholder: '请填写用户名'}) | 50 | TextInput({text: $$this.loginForm.username, placeholder: '请填写用户名'}) |
| 50 | - .backgroundColor(Color.Transparent).fontColor('#fff').fontSize(14) | 51 | + .backgroundColor(Color.Transparent).fontColor('#fff').fontSize(16) |
| 51 | .borderRadius(0).layoutWeight(1).placeholderColor('#fff') | 52 | .borderRadius(0).layoutWeight(1).placeholderColor('#fff') |
| 52 | }.width('100%').border({width:{bottom: 1}, color: '#eee'}) | 53 | }.width('100%').border({width:{bottom: 1}, color: '#eee'}) |
| 53 | Row(){ | 54 | Row(){ |
| 54 | Image($r('app.media.password')).width(20) | 55 | Image($r('app.media.password')).width(20) |
| 55 | - TextInput({text: $$this.loginForm.password, placeholder: '请填写密码'}).type(InputType.Password) | ||
| 56 | - .backgroundColor(Color.Transparent).fontColor('#fff').fontSize(14) | 56 | + TextInput({text: $$this.loginForm.password, placeholder: '请填写密码'}) |
| 57 | + .backgroundColor(Color.Transparent).fontColor('#fff').fontSize(16) | ||
| 57 | .borderRadius(0).layoutWeight(1).placeholderColor('#fff') | 58 | .borderRadius(0).layoutWeight(1).placeholderColor('#fff') |
| 58 | }.width('100%').border({width:{bottom: 1}, color: '#eee'}) | 59 | }.width('100%').border({width:{bottom: 1}, color: '#eee'}) |
| 59 | - }.margin({bottom: 10}).padding({left: 10, right: 10}) | 60 | + }.margin({bottom: 10}).padding({left: 20, right: 20}) |
| 60 | Column({space: 10}){ | 61 | Column({space: 10}){ |
| 61 | Row({space: 5}){ | 62 | Row({space: 5}){ |
| 62 | Checkbox({group: 'user' }) | 63 | Checkbox({group: 'user' }) |
| @@ -112,7 +113,7 @@ struct Login { | @@ -112,7 +113,7 @@ struct Login { | ||
| 112 | }) | 113 | }) |
| 113 | Text('记住密码').fontSize(12).fontColor('#fff') | 114 | Text('记住密码').fontSize(12).fontColor('#fff') |
| 114 | }.width('100%').justifyContent(FlexAlign.Start) | 115 | }.width('100%').justifyContent(FlexAlign.Start) |
| 115 | - }.alignItems(HorizontalAlign.Start).padding({left: 10, right: 10}) | 116 | + }.alignItems(HorizontalAlign.Start).padding({left: 20, right: 20}) |
| 116 | 117 | ||
| 117 | Button('立即登录') | 118 | Button('立即登录') |
| 118 | .width('80%').height(40) | 119 | .width('80%').height(40) |
| @@ -155,7 +156,7 @@ struct Login { | @@ -155,7 +156,7 @@ struct Login { | ||
| 155 | preferencesUtil.set('XF_PERSON_ID', personInfo.data.data.personId) | 156 | preferencesUtil.set('XF_PERSON_ID', personInfo.data.data.personId) |
| 156 | preferencesUtil.set('XF_USERNAME', personInfo.data.data.username) | 157 | preferencesUtil.set('XF_USERNAME', personInfo.data.data.username) |
| 157 | } | 158 | } |
| 158 | - router.replaceUrl({ | 159 | + router.pushUrl({ |
| 159 | url: 'pages/Index' | 160 | url: 'pages/Index' |
| 160 | }) | 161 | }) |
| 161 | }) | 162 | }) |
| @@ -17,7 +17,8 @@ struct LookRecords { | @@ -17,7 +17,8 @@ struct LookRecords { | ||
| 17 | build() { | 17 | build() { |
| 18 | Column(){ | 18 | Column(){ |
| 19 | Web({ | 19 | Web({ |
| 20 | - src: `${basePath}/report/record?id=${reportId}&token=${preferencesUtils.get('XF_TOKEN', '')}&time=${new Date().getTime()}&pid=${pid}&type=${preferencesUtils.get('XF_ROLE_NAME', '')}&username=${preferencesUtils.get('XF_USERNAME', '')}`, | 20 | + src: `${basePath}/report/record?id=${reportId}&token=${preferencesUtils.get('XF_TOKEN', '')} |
| 21 | + &time=${new Date().getTime()}&pid=${pid}&type=${preferencesUtils.get('XF_ROLE_NAME', '')}&username=${preferencesUtils.get('XF_USERNAME', '')}`, | ||
| 21 | controller: this.webviewController, | 22 | controller: this.webviewController, |
| 22 | }).mixedMode(MixedMode.All).javaScriptAccess(true).domStorageAccess(true) | 23 | }).mixedMode(MixedMode.All).javaScriptAccess(true).domStorageAccess(true) |
| 23 | }.width('100%').height('100%').backgroundColor('#f2f3f7') | 24 | }.width('100%').height('100%').backgroundColor('#f2f3f7') |
| @@ -35,7 +35,12 @@ let getTextInfo = (state: string | null) => { | @@ -35,7 +35,12 @@ let getTextInfo = (state: string | null) => { | ||
| 35 | @Component | 35 | @Component |
| 36 | struct PersonList { | 36 | struct PersonList { |
| 37 | dialogController: CustomDialogController = new CustomDialogController({ | 37 | dialogController: CustomDialogController = new CustomDialogController({ |
| 38 | - builder: AddPersonDialog(), | 38 | + builder: AddPersonDialog({ |
| 39 | + // 确认添加后的回调 | ||
| 40 | + onChange: () => { | ||
| 41 | + this.getList() | ||
| 42 | + } | ||
| 43 | + }), | ||
| 39 | cornerRadius: 10 | 44 | cornerRadius: 10 |
| 40 | }) | 45 | }) |
| 41 | @State params: QueryParams = { | 46 | @State params: QueryParams = { |
| 1 | import { webview } from '@kit.ArkWeb' | 1 | import { webview } from '@kit.ArkWeb' |
| 2 | +import NavHeader from '../components/NavHeader' | ||
| 2 | @Entry | 3 | @Entry |
| 3 | @Component | 4 | @Component |
| 4 | struct FireProtectionDetail { | 5 | struct FireProtectionDetail { |
| 5 | webviewController: webview.WebviewController = new webview.WebviewController() | 6 | webviewController: webview.WebviewController = new webview.WebviewController() |
| 6 | build() { | 7 | build() { |
| 7 | Column(){ | 8 | Column(){ |
| 9 | + NavHeader({title: '隐私政策'}) | ||
| 8 | Web({ | 10 | Web({ |
| 9 | src: `https://doc.crgx.net/privacy.html`, | 11 | src: `https://doc.crgx.net/privacy.html`, |
| 10 | controller: this.webviewController, | 12 | controller: this.webviewController, |
| 1 | -import { CSJSplashAd } from '@csj/openadsdk'; | ||
| 2 | -import { NodeController, window } from '@kit.ArkUI'; | ||
| 3 | - | ||
| 4 | -@Entry({ | ||
| 5 | - routeName: "GMSplashAdShowPage", | ||
| 6 | - storage: LocalStorage.getShared() | ||
| 7 | -}) | ||
| 8 | -@Component | ||
| 9 | -export struct SplashAdShowPage { | ||
| 10 | - @LocalStorageLink('GMSplashAd') splashAd: CSJSplashAd | undefined = undefined | ||
| 11 | - @LocalStorageLink('GMSplashSubWindow') _window: window.Window | undefined = undefined | ||
| 12 | - @LocalStorageProp('GMSplashCustomCloseBtn') splashCustomCloseBtn: boolean = false | ||
| 13 | - @State splashAdComponent: NodeController | undefined = undefined | ||
| 14 | - | ||
| 15 | - aboutToAppear(): void { | ||
| 16 | - this.splashAdComponent = this.splashAd?.getAdComponent(this.splashCustomCloseBtn, this._window) | ||
| 17 | - } | ||
| 18 | - | ||
| 19 | - onPageShow(): void { | ||
| 20 | - this._window?.setWindowLayoutFullScreen(true) | ||
| 21 | - } | ||
| 22 | - | ||
| 23 | - onPageHide(): void { | ||
| 24 | - this._window?.setWindowLayoutFullScreen(false) | ||
| 25 | - } | ||
| 26 | - | ||
| 27 | - build() { | ||
| 28 | - Stack() { | ||
| 29 | - if (this.splashAdComponent) { | ||
| 30 | - NodeContainer(this.splashAdComponent) | ||
| 31 | - } | ||
| 32 | - if (this.splashCustomCloseBtn) { | ||
| 33 | - Text('close') | ||
| 34 | - .textAlign(TextAlign.Center) | ||
| 35 | - .backgroundColor(Color.Yellow) | ||
| 36 | - .width(60) | ||
| 37 | - .height(60) | ||
| 38 | - .borderRadius(30) | ||
| 39 | - .margin({ left: 50, top: 50 }) | ||
| 40 | - .onClick(() => { | ||
| 41 | - this.closeBtnClicked() | ||
| 42 | - }) | ||
| 43 | - } | ||
| 44 | - } | ||
| 45 | - .alignContent(Alignment.TopStart) | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | - closeBtnClicked() { | ||
| 49 | - this._window?.destroyWindow() | ||
| 50 | - } | ||
| 51 | -} |
| @@ -26,7 +26,7 @@ struct StartAd { | @@ -26,7 +26,7 @@ struct StartAd { | ||
| 26 | const result = await CSJAdSdk.start() | 26 | const result = await CSJAdSdk.start() |
| 27 | if (result) { | 27 | if (result) { |
| 28 | if (result.code == 0 || result.code == 4200) { | 28 | if (result.code == 0 || result.code == 4200) { |
| 29 | - router.pushUrl({ url: 'pages/AdMainPage' }) | 29 | + router.replaceUrl({ url: 'pages/AdMainPage' }) |
| 30 | // this.loadOpenAd() | 30 | // this.loadOpenAd() |
| 31 | } else { | 31 | } else { |
| 32 | promptAction.showToast({ message: result.msg }); | 32 | promptAction.showToast({ message: result.msg }); |
| @@ -41,7 +41,13 @@ struct StartAd { | @@ -41,7 +41,13 @@ struct StartAd { | ||
| 41 | 41 | ||
| 42 | build() { | 42 | build() { |
| 43 | Column() { | 43 | Column() { |
| 44 | + Stack(){ | ||
| 45 | + Progress({ value: 0, total: 10, type: ProgressType.Ring }) | ||
| 46 | + .width(120).color('#409EFF').backgroundColor('#fff') | ||
| 47 | + .style({ strokeWidth: 10, status: ProgressStatus.LOADING }) | ||
| 48 | + | ||
| 44 | Image($r('app.media.logo')).width(60).height(60) | 49 | Image($r('app.media.logo')).width(60).height(60) |
| 50 | + } | ||
| 45 | }.width('100%').height('100%').justifyContent(FlexAlign.Center) | 51 | }.width('100%').height('100%').justifyContent(FlexAlign.Center) |
| 46 | } | 52 | } |
| 47 | } | 53 | } |
| @@ -4,17 +4,25 @@ import { downFile } from '../utils/downFile' | @@ -4,17 +4,25 @@ import { downFile } from '../utils/downFile' | ||
| 4 | import { router } from '@kit.ArkUI' | 4 | import { router } from '@kit.ArkUI' |
| 5 | import PhotoBrowser from '../dialog/PhotoBrowserDialog' | 5 | import PhotoBrowser from '../dialog/PhotoBrowserDialog' |
| 6 | import NavHeader from '../components/NavHeader' | 6 | import NavHeader from '../components/NavHeader' |
| 7 | +interface showVideoOrImg { | ||
| 8 | + cosKey: string | null; | ||
| 9 | + itemName: string; | ||
| 10 | + videoList?: string[]; | ||
| 11 | + imgList?: string[]; | ||
| 12 | +} | ||
| 13 | +interface VideoOrImgList { | ||
| 14 | + videoList: string[]; | ||
| 15 | + imgList: string[]; | ||
| 16 | +} | ||
| 7 | interface routerParams { | 17 | interface routerParams { |
| 8 | - cosKey: string | ||
| 9 | - relateId: number | 18 | + cosKeyList: showVideoOrImg[] |
| 10 | } | 19 | } |
| 11 | let routerQuery = router.getParams() as routerParams | 20 | let routerQuery = router.getParams() as routerParams |
| 12 | @Entry | 21 | @Entry |
| 13 | @Component | 22 | @Component |
| 14 | struct DownLoadImage { | 23 | struct DownLoadImage { |
| 15 | - @State imgList: string[] = [] | ||
| 16 | - @State videoList: string[] = [] | ||
| 17 | - @State cosKeyData: string[] = routerQuery?.cosKey.split(';') | 24 | + @State cosKeyData: showVideoOrImg[] = routerQuery?.cosKeyList |
| 25 | + @State showCosKeyList: showVideoOrImg[] = [] | ||
| 18 | @State viewImg: string[] = [] | 26 | @State viewImg: string[] = [] |
| 19 | @State viewVideo: string[] = [] | 27 | @State viewVideo: string[] = [] |
| 20 | @State saveButtonOptions: SaveButtonOptions = { | 28 | @State saveButtonOptions: SaveButtonOptions = { |
| @@ -28,51 +36,76 @@ struct DownLoadImage { | @@ -28,51 +36,76 @@ struct DownLoadImage { | ||
| 28 | offset: { dx: 0, dy: 0 }, | 36 | offset: { dx: 0, dy: 0 }, |
| 29 | alignment: DialogAlignment.Top, | 37 | alignment: DialogAlignment.Top, |
| 30 | }) | 38 | }) |
| 31 | - aboutToAppear() { | ||
| 32 | - this.cosKeyData.forEach((item: string) => { | ||
| 33 | - let newArr = item.split('.') | ||
| 34 | - let index = newArr.length - 1 | ||
| 35 | - if(newArr[index] == 'mp4') { | ||
| 36 | - this.videoList.push(item) | ||
| 37 | - }else { | ||
| 38 | - this.imgList.push(item) | 39 | + async aboutToAppear() { |
| 40 | + this.showCosKeyList = await Promise.all(this.cosKeyData.map(async (item: showVideoOrImg) => { | ||
| 41 | + if (item.cosKey) { | ||
| 42 | + const arrList: VideoOrImgList | [] = await this.getVideoOrImgUrl(item.cosKey) | ||
| 43 | + if (!Array.isArray(arrList)) { | ||
| 44 | + item.videoList = arrList.videoList | ||
| 45 | + item.imgList = arrList.imgList | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + return item | ||
| 49 | + })) | ||
| 50 | + } | ||
| 51 | + // 请求获取图片或视频链接 | ||
| 52 | + getVideoOrImgUrl = async (cosKey: string | null) => { | ||
| 53 | + let result: VideoOrImgList | [] = this.filterVideoOrImg(cosKey) | ||
| 54 | + if (!Array.isArray(result)) { | ||
| 55 | + let videoData: string[] = await Promise.all(result.videoList.map(async (item: string) => { | ||
| 56 | + const res: AxiosResponse<downloadUrl> = await getDownloadUrl(item, 0) | ||
| 57 | + return res.data.data | ||
| 58 | + })) | ||
| 59 | + let imgData: string[] = await Promise.all(result.imgList.map(async (item: string) => { | ||
| 60 | + const res: AxiosResponse<downloadUrl> = await getDownloadUrl(item, 0) | ||
| 61 | + return res.data.data | ||
| 62 | + })) | ||
| 63 | + result = { | ||
| 64 | + videoList: videoData, | ||
| 65 | + imgList: imgData | ||
| 66 | + } | ||
| 67 | + } | ||
| 68 | + return result | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + // 筛选图片或者视频 | ||
| 72 | + filterVideoOrImg = (cosKey: string | null): VideoOrImgList | [] => { | ||
| 73 | + let urlList: string[] | undefined = cosKey?.split(';') | ||
| 74 | + let videoList: string[] = [] | ||
| 75 | + let imgList: string[] = [] | ||
| 76 | + if(urlList === undefined) return [] | ||
| 77 | + urlList.forEach((item: string) => { | ||
| 78 | + let newItemList: string[] = item.split('.') | ||
| 79 | + if(newItemList[newItemList.length - 1] == 'mp4' || newItemList[newItemList.length - 1] == 'mkv'){ | ||
| 80 | + videoList.push(item) | ||
| 81 | + } else { | ||
| 82 | + imgList.push(item) | ||
| 39 | } | 83 | } |
| 40 | }) | 84 | }) |
| 41 | - this.imgList.forEach(async (item: string) => { | ||
| 42 | - const imgDta: AxiosResponse<downloadUrl> = await getDownloadUrl(item, 0) | ||
| 43 | - this.viewImg.push(imgDta.data.data) | ||
| 44 | - }) | ||
| 45 | - this.videoList.forEach(async (item: string) => { | ||
| 46 | - const imgDta: AxiosResponse<downloadUrl> = await getDownloadUrl(item, 0) | ||
| 47 | - this.viewVideo.push(imgDta.data.data) | ||
| 48 | - }) | 85 | + |
| 86 | + return { | ||
| 87 | + videoList, | ||
| 88 | + imgList | ||
| 89 | + } | ||
| 49 | } | 90 | } |
| 91 | + | ||
| 92 | + | ||
| 50 | build() { | 93 | build() { |
| 51 | Column(){ | 94 | Column(){ |
| 52 | - NavHeader({title: '下载图片'}) | 95 | + NavHeader({title: '视频/图片下载'}) |
| 53 | List(){ | 96 | List(){ |
| 97 | + ForEach(this.showCosKeyList, (item:showVideoOrImg ) => { | ||
| 54 | ListItem(){ | 98 | ListItem(){ |
| 55 | Column({ space: 10 }) { | 99 | Column({ space: 10 }) { |
| 56 | - Row(){ | ||
| 57 | Row({space: 5}){ | 100 | Row({space: 5}){ |
| 58 | Text().width(2).height(20).backgroundColor('#1890ff') | 101 | Text().width(2).height(20).backgroundColor('#1890ff') |
| 59 | - Text('图片').fontSize(14).fontWeight(600) | ||
| 60 | - } | ||
| 61 | - Text('预览图片') | ||
| 62 | - .fontSize(14).fontColor('#fff').backgroundColor('#1890ff') | ||
| 63 | - .padding({left: 15, right: 15, top: 2, bottom: 2}) | ||
| 64 | - .borderRadius(4) | ||
| 65 | - .onClick(() => { | ||
| 66 | - this.photoBrowserController.open() | ||
| 67 | - }) | ||
| 68 | - } | ||
| 69 | - .justifyContent(FlexAlign.SpaceBetween) | ||
| 70 | - .width('100%') | 102 | + Text(item.itemName).fontSize(14).fontWeight(600) |
| 103 | + }.width('100%') | ||
| 71 | GridRow({ columns: 2, gutter: 10 }) { | 104 | GridRow({ columns: 2, gutter: 10 }) { |
| 72 | - ForEach(this.viewImg, (item: string) => { | 105 | + ForEach(item.imgList, (childrenImg: string) => { |
| 73 | GridCol() { | 106 | GridCol() { |
| 74 | Column({space: 10}){ | 107 | Column({space: 10}){ |
| 75 | - Image(item) | 108 | + Image(childrenImg) |
| 76 | .width('100%') | 109 | .width('100%') |
| 77 | .height(150) | 110 | .height(150) |
| 78 | .borderRadius(4) | 111 | .borderRadius(4) |
| @@ -81,7 +114,7 @@ struct DownLoadImage { | @@ -81,7 +114,7 @@ struct DownLoadImage { | ||
| 81 | // 创建安全控件按钮 | 114 | // 创建安全控件按钮 |
| 82 | .onClick(async (event, result: SaveButtonOnClickResult) => { | 115 | .onClick(async (event, result: SaveButtonOnClickResult) => { |
| 83 | if (result == SaveButtonOnClickResult.SUCCESS) { | 116 | if (result == SaveButtonOnClickResult.SUCCESS) { |
| 84 | - downFile(item, 'jpg') | 117 | + downFile(childrenImg, 'jpg') |
| 85 | } | 118 | } |
| 86 | }) | 119 | }) |
| 87 | } | 120 | } |
| @@ -89,39 +122,25 @@ struct DownLoadImage { | @@ -89,39 +122,25 @@ struct DownLoadImage { | ||
| 89 | } | 122 | } |
| 90 | }) | 123 | }) |
| 91 | } | 124 | } |
| 92 | - } | ||
| 93 | - }.visibility(this.viewImg.length == 0 ? Visibility.None : Visibility.Visible) | ||
| 94 | - ListItem(){ | ||
| 95 | - Column({ space: 10 }) { | ||
| 96 | - Row(){ | ||
| 97 | - Row({space: 5}){ | ||
| 98 | - Text().width(2).height(20).backgroundColor('#1890ff') | ||
| 99 | - Text('视频').fontSize(14).fontWeight(600) | ||
| 100 | - } | ||
| 101 | - } | ||
| 102 | - .justifyContent(FlexAlign.Start) | ||
| 103 | - .width('100%') | ||
| 104 | GridRow({ columns: 1}) { | 125 | GridRow({ columns: 1}) { |
| 105 | - ForEach(this.viewVideo, (item: string) => { | 126 | + ForEach(item.videoList, (childrenVideo: string) => { |
| 106 | GridCol() { | 127 | GridCol() { |
| 107 | Column({ space: 10}){ | 128 | Column({ space: 10}){ |
| 108 | - Video({ src: item }).width('100%').height(300).controls(true) | 129 | + Video({ src: childrenVideo }).width('100%').height(300) |
| 109 | SaveButton(this.saveButtonOptions) | 130 | SaveButton(this.saveButtonOptions) |
| 110 | // 创建安全控件按钮 | 131 | // 创建安全控件按钮 |
| 111 | .onClick(async (event, result: SaveButtonOnClickResult) => { | 132 | .onClick(async (event, result: SaveButtonOnClickResult) => { |
| 112 | if (result == SaveButtonOnClickResult.SUCCESS) { | 133 | if (result == SaveButtonOnClickResult.SUCCESS) { |
| 113 | - downFile(item, 'mp4') | 134 | + downFile(childrenVideo, 'mp4') |
| 114 | } | 135 | } |
| 115 | }) | 136 | }) |
| 116 | } | 137 | } |
| 117 | - } | ||
| 118 | - .margin({ | ||
| 119 | - top: 10 | ||
| 120 | - }) | 138 | + }.margin({ top: 10 }) |
| 121 | }) | 139 | }) |
| 122 | } | 140 | } |
| 123 | } | 141 | } |
| 124 | - }.visibility(this.viewVideo.length == 0 ? Visibility.None : Visibility.Visible) | 142 | + } |
| 143 | + }) | ||
| 125 | }.padding(10) | 144 | }.padding(10) |
| 126 | } | 145 | } |
| 127 | } | 146 | } |
entry/src/main/ets/utils/CreateCamera.ets
0 → 100644
| 1 | +import { media } from '@kit.MediaKit'; | ||
| 2 | +import { BusinessError } from '@kit.BasicServicesKit'; | ||
| 3 | +import { fileIo as fs, fileUri } from '@kit.CoreFileKit'; | ||
| 4 | +import { photoAccessHelper } from '@kit.MediaLibraryKit'; | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | +const TAG = 'VideoRecorderDemo:'; | ||
| 9 | +export class VideoRecorderDemo { | ||
| 10 | + private context: Context; | ||
| 11 | + constructor() { | ||
| 12 | + this.context = getContext(this); | ||
| 13 | + } | ||
| 14 | + private avRecorder: media.AVRecorder | undefined = undefined; | ||
| 15 | + private videoOutSurfaceId: string = ""; | ||
| 16 | + private avProfile: media.AVRecorderProfile = { | ||
| 17 | + fileFormat : media.ContainerFormatType.CFT_MPEG_4, // 视频文件封装格式,只支持MP4 | ||
| 18 | + videoBitrate : 100000, // 视频比特率 | ||
| 19 | + videoCodec : media.CodecMimeType.VIDEO_AVC, // 视频文件编码格式,支持avc格式 | ||
| 20 | + videoFrameWidth : 640, // 视频分辨率的宽 | ||
| 21 | + videoFrameHeight : 480, // 视频分辨率的高 | ||
| 22 | + videoFrameRate : 30 // 视频帧率 | ||
| 23 | + }; | ||
| 24 | + private avConfig: media.AVRecorderConfig = { | ||
| 25 | + videoSourceType : media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, // 视频源类型,支持YUV和ES两种格式 | ||
| 26 | + profile : this.avProfile, | ||
| 27 | + url : 'fd://35', // 参考应用文件访问与管理开发示例新建并读写一个文件 | ||
| 28 | + rotation : 0 // 视频旋转角度,默认为0不旋转,支持的值为0、90、180、270 | ||
| 29 | + }; | ||
| 30 | + | ||
| 31 | + private uriPath: string = ''; // 文件uri,可用于安全控件保存媒体资源 | ||
| 32 | + private filePath: string = ''; // 文件路径 | ||
| 33 | + private fileFd: number = 0; | ||
| 34 | + | ||
| 35 | + // 创建文件以及设置avConfig.url | ||
| 36 | + async createAndSetFd() { | ||
| 37 | + const path: string = this.context.filesDir + '/example.mp4'; // 文件沙箱路径,文件后缀名应与封装格式对应 | ||
| 38 | + const videoFile: fs.File = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); | ||
| 39 | + this.avConfig.url = 'fd://' + videoFile.fd; // 设置url | ||
| 40 | + this.fileFd = videoFile.fd; // 文件fd | ||
| 41 | + this.filePath = path; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + // 注册avRecorder回调函数 | ||
| 45 | + setAvRecorderCallback() { | ||
| 46 | + if (this.avRecorder != undefined) { | ||
| 47 | + // 状态机变化回调函数 | ||
| 48 | + this.avRecorder.on('stateChange', (state: media.AVRecorderState, reason: media.StateChangeReason) => { | ||
| 49 | + console.info(TAG + 'current state is: ' + state); | ||
| 50 | + }) | ||
| 51 | + // 错误上报回调函数 | ||
| 52 | + this.avRecorder.on('error', (err: BusinessError) => { | ||
| 53 | + console.error(TAG + 'error ocConstantSourceNode, error message is ' + err); | ||
| 54 | + }) | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + // 相机相关准备工作 | ||
| 59 | + async prepareCamera() { | ||
| 60 | + // 具体实现查看相机资料 | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + // 启动相机出流 | ||
| 64 | + async startCameraOutput() { | ||
| 65 | + // 调用VideoOutput的start接口开始录像输出 | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + // 停止相机出流 | ||
| 69 | + async stopCameraOutput() { | ||
| 70 | + // 调用VideoOutput的stop接口停止录像输出 | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + // 释放相机实例 | ||
| 74 | + async releaseCamera() { | ||
| 75 | + // 释放相机准备阶段创建出的实例 | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + // 开始录制对应的流程 | ||
| 79 | + async startRecordingProcess() { | ||
| 80 | + if (this.avRecorder === undefined) { | ||
| 81 | + // 1.创建录制实例; | ||
| 82 | + this.avRecorder = await media.createAVRecorder(); | ||
| 83 | + this.setAvRecorderCallback(); | ||
| 84 | + } | ||
| 85 | + // 2. 获取录制文件fd;获取到的值传递给avConfig里的url,实现略 | ||
| 86 | + // 3.配置录制参数完成准备工作 | ||
| 87 | + await this.avRecorder.prepare(this.avConfig); | ||
| 88 | + this.videoOutSurfaceId = await this.avRecorder.getInputSurface(); | ||
| 89 | + // 4.完成相机相关准备工作 | ||
| 90 | + await this.prepareCamera(); | ||
| 91 | + // 5.启动相机出流 | ||
| 92 | + await this.startCameraOutput(); | ||
| 93 | + // 6. 启动录制 | ||
| 94 | + await this.avRecorder.start(); | ||
| 95 | + | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + // 暂停录制对应的流程 | ||
| 99 | + async pauseRecordingProcess() { | ||
| 100 | + if (this.avRecorder != undefined && this.avRecorder.state === 'started') { // 仅在started状态下调用pause为合理状态切换 | ||
| 101 | + await this.avRecorder.pause(); | ||
| 102 | + await this.stopCameraOutput(); // 停止相机出流 | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + // 恢复录制对应的流程 | ||
| 107 | + async resumeRecordingProcess() { | ||
| 108 | + if (this.avRecorder != undefined && this.avRecorder.state === 'paused') { // 仅在paused状态下调用resume为合理状态切换 | ||
| 109 | + await this.startCameraOutput(); // 启动相机出流 | ||
| 110 | + await this.avRecorder.resume(); | ||
| 111 | + } | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + async stopRecordingProcess() { | ||
| 115 | + if (this.avRecorder != undefined) { | ||
| 116 | + // 1. 停止录制 | ||
| 117 | + if (this.avRecorder.state === 'started' | ||
| 118 | + || this.avRecorder.state === 'paused' ) { // 仅在started或者paused状态下调用stop为合理状态切换 | ||
| 119 | + await this.avRecorder.stop(); | ||
| 120 | + await this.stopCameraOutput(); | ||
| 121 | + } | ||
| 122 | + // 2.重置 | ||
| 123 | + await this.avRecorder.reset(); | ||
| 124 | + // 3.释放录制实例 | ||
| 125 | + await this.avRecorder.release(); | ||
| 126 | + // 4.文件录制完成后,关闭fd,实现略 | ||
| 127 | + await fs.close(this.fileFd); | ||
| 128 | + // 5.释放相机相关实例 | ||
| 129 | + await this.releaseCamera(); | ||
| 130 | + } | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + // 安全控件保存媒体资源至图库 | ||
| 134 | + async saveRecorderAsset() { | ||
| 135 | + let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context); | ||
| 136 | + // 需要确保uriPath对应的资源存在 | ||
| 137 | + this.uriPath = fileUri.getUriFromPath(this.filePath); // 获取录制文件的uri,用于安全控件保存至图库 | ||
| 138 | + let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = | ||
| 139 | + photoAccessHelper.MediaAssetChangeRequest.createVideoAssetRequest(this.context, this.uriPath); | ||
| 140 | + await phAccessHelper.applyChanges(assetChangeRequest); | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + // 一个完整的【开始录制-暂停录制-恢复录制-停止录制】示例 | ||
| 144 | + async videoRecorderDemo() { | ||
| 145 | + await this.startRecordingProcess(); // 开始录制 | ||
| 146 | + // 用户此处可以自行设置录制时长,例如通过设置休眠阻止代码执行 | ||
| 147 | + await this.pauseRecordingProcess(); //暂停录制 | ||
| 148 | + await this.resumeRecordingProcess(); // 恢复录制 | ||
| 149 | + await this.stopRecordingProcess(); // 停止录制 | ||
| 150 | + // 安全控件保存媒体资源至图库 | ||
| 151 | + await this.saveRecorderAsset(); | ||
| 152 | + } | ||
| 153 | +} |
entry/src/main/ets/utils/FileUtil.ets
0 → 100644
| 1 | +import fs from '@ohos.file.fs'; | ||
| 2 | +import buffer from '@ohos.buffer'; | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +// 大小和单位 | ||
| 6 | +const GB_MAGNITUDE: number = 1024 * 1024 * 1024 | ||
| 7 | +const MB_MAGNITUDE: number = 1024 * 1024 | ||
| 8 | +const KB_MAGNITUDE: number = 1024 | ||
| 9 | +const GB_SYMBOL: string = 'GB' | ||
| 10 | +const MB_SYMBOL: string = 'MB' | ||
| 11 | +const KB_SYMBOL: string = 'KB' | ||
| 12 | +const BYTE_SYMBOL: string = 'B' | ||
| 13 | + | ||
| 14 | +export class FileUtil { | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * 新建并打开文件 | ||
| 19 | + */ | ||
| 20 | + static createOrOpen(path: string) : fs.File{ | ||
| 21 | + let isExist = fs.accessSync(path); | ||
| 22 | + let file: fs.File; | ||
| 23 | + if(isExist) { | ||
| 24 | + file = fs.openSync(path, fs.OpenMode.READ_WRITE); | ||
| 25 | + }else { | ||
| 26 | + file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE) | ||
| 27 | + } | ||
| 28 | + return file; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 保存arrayBuffer到文件 | ||
| 34 | + * @param path | ||
| 35 | + * @param arrayBuffer | ||
| 36 | + * @returns | ||
| 37 | + */ | ||
| 38 | + static writeBufferToFile(path: string, arrayBuffer: ArrayBuffer): number { | ||
| 39 | + | ||
| 40 | + try { | ||
| 41 | + let file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); | ||
| 42 | + let value = fs.writeSync(file.fd, arrayBuffer); | ||
| 43 | + fs.closeSync(file); | ||
| 44 | + return value; | ||
| 45 | + }catch (err){ | ||
| 46 | + console.log("FileUtil", "writeFile err:" + err); | ||
| 47 | + return -1; | ||
| 48 | + } | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + | ||
| 52 | + /** | ||
| 53 | + * 保存文本到文件 | ||
| 54 | + * @param path | ||
| 55 | + * @param text | ||
| 56 | + * @returns | ||
| 57 | + */ | ||
| 58 | + static writeStrToFile(path: string, text: string): number { | ||
| 59 | + try { | ||
| 60 | + let file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); | ||
| 61 | + let value = fs.writeSync(file.fd, text); | ||
| 62 | + fs.closeSync(file); | ||
| 63 | + return value; | ||
| 64 | + }catch (err) { | ||
| 65 | + console.log("FileUtil", "writeFile err:" + err); | ||
| 66 | + return -1; | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | + | ||
| 72 | +export class CommonConstants { | ||
| 73 | + /** | ||
| 74 | + * ShowToast duration. | ||
| 75 | + */ | ||
| 76 | + static readonly SHOW_TOAST_DURATION: number = 4000; | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * ShowToast bottom. | ||
| 80 | + */ | ||
| 81 | + static readonly SHOW_TOAST_BOTTOM: number = 108; | ||
| 82 | + | ||
| 83 | + /** | ||
| 84 | + * Image size. | ||
| 85 | + */ | ||
| 86 | + static readonly IMAGE_SIZE: number = 200; | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * The full percentage of component. | ||
| 90 | + */ | ||
| 91 | + static readonly FULL_PERCENT: string = '100%'; | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * The ninety percent of the components. | ||
| 95 | + */ | ||
| 96 | + static readonly NINETY_PERCENT: string = '90%'; | ||
| 97 | + | ||
| 98 | + /** | ||
| 99 | + * The seventy percent of the components. | ||
| 100 | + */ | ||
| 101 | + static readonly SEVENTY_PERCENT: string = '70%'; | ||
| 102 | + | ||
| 103 | + /** | ||
| 104 | + * The fifteen percent of the bottom of the margin. | ||
| 105 | + */ | ||
| 106 | + static readonly FIFTEEN_PERCENT: string = '15%'; | ||
| 107 | +} |
| 1 | -// export default 'https://xfwbzshd.crgx.net' | ||
| 2 | -// 后端域名 | ||
| 3 | -export default 'https://xfappht.crgx.net' | 1 | +export default 'https://xfwbzshd.crgx.net' |
| 2 | +// 正式后端域名 | ||
| 3 | +// export default 'https://xfappht.crgx.net' | ||
| 4 | // 前端地址 | 4 | // 前端地址 |
| 5 | export const basePath = 'https://xfwbzs.crgx.net' | 5 | export const basePath = 'https://xfwbzs.crgx.net' |
| @@ -4,7 +4,7 @@ import { promptAction } from '@kit.ArkUI' | @@ -4,7 +4,7 @@ import { promptAction } from '@kit.ArkUI' | ||
| 4 | import { photoAccessHelper } from '@kit.MediaLibraryKit' | 4 | import { photoAccessHelper } from '@kit.MediaLibraryKit' |
| 5 | import { getCosKey, cosKeyTest, cosKeyData, uploadVideoOrImg } from '../api/cosKey' | 5 | import { getCosKey, cosKeyTest, cosKeyData, uploadVideoOrImg } from '../api/cosKey' |
| 6 | import { AxiosResponse } from '@ohos/axios' | 6 | import { AxiosResponse } from '@ohos/axios' |
| 7 | - | 7 | +import { camera, cameraPicker } from '@kit.CameraKit' |
| 8 | 8 | ||
| 9 | // 选择一张图片或视频 | 9 | // 选择一张图片或视频 |
| 10 | export async function selectImgOrVideo(){ | 10 | export async function selectImgOrVideo(){ |
| @@ -18,6 +18,20 @@ export async function selectImgOrVideo(){ | @@ -18,6 +18,20 @@ export async function selectImgOrVideo(){ | ||
| 18 | return photos.photoUris[0] // 返回文件路径 | 18 | return photos.photoUris[0] // 返回文件路径 |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | +// 相机拍照 | ||
| 22 | +export async function selectImgByCamera(){ | ||
| 23 | + try { | ||
| 24 | + let pickerProfile: cameraPicker.PickerProfile = { | ||
| 25 | + cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK // 设置相机位置 | ||
| 26 | + } | ||
| 27 | + let pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(getContext(), | ||
| 28 | + [cameraPicker.PickerMediaType.PHOTO, cameraPicker.PickerMediaType.PHOTO], pickerProfile); | ||
| 29 | + } catch (error) { | ||
| 30 | + let err = error as BusinessError; | ||
| 31 | + console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`) | ||
| 32 | + } | ||
| 33 | +} | ||
| 34 | + | ||
| 21 | /** | 35 | /** |
| 22 | * 上传文件(通过uploadTask实现) | 36 | * 上传文件(通过uploadTask实现) |
| 23 | * @param context context | 37 | * @param context context |
| 1 | import { photoAccessHelper } from '@kit.MediaLibraryKit' | 1 | import { photoAccessHelper } from '@kit.MediaLibraryKit' |
| 2 | import fs from '@ohos.file.fs'; | 2 | import fs from '@ohos.file.fs'; |
| 3 | import { request, BusinessError } from '@kit.BasicServicesKit'; | 3 | import { request, BusinessError } from '@kit.BasicServicesKit'; |
| 4 | +import { cameraPicker as picker, camera } from '@kit.CameraKit'; | ||
| 5 | +import { common } from '@kit.AbilityKit'; | ||
| 4 | import preferencesUtils from '../utils/preferences' | 6 | import preferencesUtils from '../utils/preferences' |
| 7 | +import { promptAction } from '@kit.ArkUI' | ||
| 8 | +import { fileIo, fileUri } from '@kit.CoreFileKit' | ||
| 9 | +import { VideoCompressor, CompressQuality, CompressorResponseCode } from '@ohos/videocompressor' | ||
| 10 | + | ||
| 11 | +let mContext = getContext(this) as common.Context; | ||
| 5 | export interface uploadResult { | 12 | export interface uploadResult { |
| 6 | code?: number | 13 | code?: number |
| 7 | msg?: string | 14 | msg?: string |
| @@ -23,6 +30,67 @@ export async function selectImg(){ | @@ -23,6 +30,67 @@ export async function selectImg(){ | ||
| 23 | return photos.photoUris[0] // 返回图片路径 | 30 | return photos.photoUris[0] // 返回图片路径 |
| 24 | } | 31 | } |
| 25 | 32 | ||
| 33 | +// 使用相机拍照 | ||
| 34 | +export async function cameraPickerImg() { | ||
| 35 | + let pathDir = getContext().cacheDir; | ||
| 36 | + let fileName = `${new Date().getTime()}` | ||
| 37 | + let filePath = pathDir + `/${fileName}.tmp` | ||
| 38 | + fileIo.createRandomAccessFileSync(filePath, fileIo.OpenMode.CREATE); | ||
| 39 | + let uri = fileUri.getUriFromPath(filePath); | ||
| 40 | + let pickerProfile: picker.PickerProfile = { | ||
| 41 | + cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK, | ||
| 42 | + saveUri: uri | ||
| 43 | + }; | ||
| 44 | + try { | ||
| 45 | + let result: picker.PickerResult = await picker.pick(getContext(), [picker.PickerMediaType.PHOTO], pickerProfile); | ||
| 46 | + console.info(`picker resultCode: ${result.resultCode},resultUri: ${result.resultUri},mediaType: ${result.mediaType}`); | ||
| 47 | + return result.resultUri | ||
| 48 | + } catch (error) { | ||
| 49 | + let err = error as BusinessError; | ||
| 50 | + console.error(`the pick call failed. error code: ${err.code}`); | ||
| 51 | + return '' | ||
| 52 | + } | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +// 使用相机录像 | ||
| 56 | +export async function cameraPickerVideo() { | ||
| 57 | + let pathDir = getContext().cacheDir; | ||
| 58 | + let fileName = `${new Date().getTime()}` | ||
| 59 | + let filePath = pathDir + `/${fileName}.tmp` | ||
| 60 | + fileIo.createRandomAccessFileSync(filePath, fileIo.OpenMode.CREATE); | ||
| 61 | + let uri = fileUri.getUriFromPath(filePath); | ||
| 62 | + let pickerProfile: picker.PickerProfile = { | ||
| 63 | + cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK, | ||
| 64 | + saveUri: uri, | ||
| 65 | + videoDuration: 120 | ||
| 66 | + }; | ||
| 67 | + try { | ||
| 68 | + let result: picker.PickerResult = await picker.pick(getContext(), [picker.PickerMediaType.VIDEO], pickerProfile); | ||
| 69 | + console.info(`picker resultCode: ${result.resultCode},resultUri: ${result.resultUri},mediaType: ${result.mediaType}`); | ||
| 70 | + return result.resultUri | ||
| 71 | + } catch (error) { | ||
| 72 | + let err = error as BusinessError; | ||
| 73 | + console.error(`the pick call failed. error code: ${err.code}`); | ||
| 74 | + return '' | ||
| 75 | + } | ||
| 76 | +} | ||
| 77 | + | ||
| 78 | + | ||
| 79 | +// 视频解码压缩 | ||
| 80 | +export async function videoCompressMethod(selectFilePath: string) { | ||
| 81 | + let videoCompressor = new VideoCompressor(); | ||
| 82 | + const data = await videoCompressor.compressVideo(getContext(), selectFilePath, CompressQuality.COMPRESS_QUALITY_LOW) // 分别对应3个压缩质量 COMPRESS_QUALITY_HIGH,COMPRESS_QUALITY_MEDIUM, COMPRESS_QUALITY_LOW | ||
| 83 | + if (data.code == CompressorResponseCode.SUCCESS) { | ||
| 84 | + //outputPath: 压缩后的文件地址 | ||
| 85 | + console.log("videoCompressor HIGH message:" + data.message + "--outputPath:" + data.outputPath); | ||
| 86 | + return data.outputPath | ||
| 87 | + } else { | ||
| 88 | + console.log("videoCompressor HIGH code:" + data.code + "--error message:" + data.message); | ||
| 89 | + return '' | ||
| 90 | + } | ||
| 91 | +} | ||
| 92 | + | ||
| 93 | + | ||
| 26 | 94 | ||
| 27 | // 拷贝图片路径到缓存 | 95 | // 拷贝图片路径到缓存 |
| 28 | export async function copyCachePath(systemPhotoImagePath: string) { | 96 | export async function copyCachePath(systemPhotoImagePath: string) { |
| @@ -42,6 +110,8 @@ export async function uploadFile() { | @@ -42,6 +110,8 @@ export async function uploadFile() { | ||
| 42 | // 1. 完成图片上传并获得上传对象 | 110 | // 1. 完成图片上传并获得上传对象 |
| 43 | try { | 111 | try { |
| 44 | let systemPhotoImagePath = await selectImg() // 选择图片 | 112 | let systemPhotoImagePath = await selectImg() // 选择图片 |
| 113 | + // let systemPhotoImagePath = await cameraPickerImg() // 使用相机拍照 | ||
| 114 | + if(systemPhotoImagePath == '') return promptAction.showToast({message: '未选择图片'}) | ||
| 45 | const fileData: string[] = await copyCachePath(systemPhotoImagePath) | 115 | const fileData: string[] = await copyCachePath(systemPhotoImagePath) |
| 46 | let uploader = await request.uploadFile(getContext(),{ // 上传图片 | 116 | let uploader = await request.uploadFile(getContext(),{ // 上传图片 |
| 47 | url:'http://xfwbzshd.crgx.net/common/upload', // 请求地址 | 117 | url:'http://xfwbzshd.crgx.net/common/upload', // 请求地址 |
| @@ -8,7 +8,7 @@ | @@ -8,7 +8,7 @@ | ||
| 8 | }, | 8 | }, |
| 9 | { | 9 | { |
| 10 | "name": "ohos.permission.READ_MEDIA", | 10 | "name": "ohos.permission.READ_MEDIA", |
| 11 | - "reason": "$string:EntryAbility1_desc", | 11 | + "reason": "$string:EntryAbilityReadFile_desc", |
| 12 | "usedScene": { | 12 | "usedScene": { |
| 13 | "abilities": [ | 13 | "abilities": [ |
| 14 | "EntryAbility" | 14 | "EntryAbility" |
| @@ -18,13 +18,43 @@ | @@ -18,13 +18,43 @@ | ||
| 18 | }, | 18 | }, |
| 19 | { | 19 | { |
| 20 | "name": "ohos.permission.WRITE_MEDIA", | 20 | "name": "ohos.permission.WRITE_MEDIA", |
| 21 | - "reason": "$string:EntryAbility1_desc", | 21 | + "reason": "$string:EntryAbilityReadFile_desc", |
| 22 | "usedScene": { | 22 | "usedScene": { |
| 23 | "abilities": [ | 23 | "abilities": [ |
| 24 | "EntryAbility" | 24 | "EntryAbility" |
| 25 | ], | 25 | ], |
| 26 | "when": "inuse" | 26 | "when": "inuse" |
| 27 | } | 27 | } |
| 28 | + }, | ||
| 29 | + { | ||
| 30 | + "name": "ohos.permission.MICROPHONE", | ||
| 31 | + "reason": "$string:EntryAbilityMicroPhone_desc", | ||
| 32 | + "usedScene": { | ||
| 33 | + "abilities": [ | ||
| 34 | + "EntryAbility" | ||
| 35 | + ], | ||
| 36 | + "when": "inuse" | ||
| 37 | + } | ||
| 38 | + }, | ||
| 39 | + { | ||
| 40 | + "name": "ohos.permission.MEDIA_LOCATION", | ||
| 41 | + "reason": "$string:EntryAbilityMedia_desc", | ||
| 42 | + "usedScene": { | ||
| 43 | + "abilities": [ | ||
| 44 | + "FormAbility" | ||
| 45 | + ], | ||
| 46 | + "when":"always" | ||
| 47 | + } | ||
| 48 | + }, | ||
| 49 | + { | ||
| 50 | + "name": "ohos.permission.CAMERA", | ||
| 51 | + "reason": "$string:EntryAbilityCamera_desc", | ||
| 52 | + "usedScene": { | ||
| 53 | + "abilities": [ | ||
| 54 | + "EntryAbility" | ||
| 55 | + ], | ||
| 56 | + "when": "always" | ||
| 57 | + } | ||
| 28 | } | 58 | } |
| 29 | ], | 59 | ], |
| 30 | "description": "$string:module_desc", | 60 | "description": "$string:module_desc", |
不能预览此文件类型
不能预览此文件类型
| @@ -9,18 +9,30 @@ | @@ -9,18 +9,30 @@ | ||
| 9 | "value": "description" | 9 | "value": "description" |
| 10 | }, | 10 | }, |
| 11 | { | 11 | { |
| 12 | - "name": "EntryAbility1_desc", | 12 | + "name": "EntryAbilityReadFile_desc", |
| 13 | "value": "读取文件" | 13 | "value": "读取文件" |
| 14 | }, | 14 | }, |
| 15 | { | 15 | { |
| 16 | - "name": "EntryAbility2_desc", | 16 | + "name": "EntryAbilityReadPhoto_desc", |
| 17 | "value": "读取相册" | 17 | "value": "读取相册" |
| 18 | }, | 18 | }, |
| 19 | { | 19 | { |
| 20 | - "name": "EntryAbility3_desc", | 20 | + "name": "EntryAbilitySharePlate_desc", |
| 21 | "value": "读取剪切板" | 21 | "value": "读取剪切板" |
| 22 | }, | 22 | }, |
| 23 | { | 23 | { |
| 24 | + "name": "EntryAbilityMedia_desc", | ||
| 25 | + "value": "访问你的地理位置" | ||
| 26 | + }, | ||
| 27 | + { | ||
| 28 | + "name": "EntryAbilityCamera_desc", | ||
| 29 | + "value": "使用相机拍照录像" | ||
| 30 | + }, | ||
| 31 | + { | ||
| 32 | + "name": "EntryAbilityMicroPhone_desc", | ||
| 33 | + "value": "使用你的麦克风录音" | ||
| 34 | + }, | ||
| 35 | + { | ||
| 24 | "name": "EntryAbility_label", | 36 | "name": "EntryAbility_label", |
| 25 | "value": "消防维保助手" | 37 | "value": "消防维保助手" |
| 26 | }, | 38 | }, |
10.4 KB
15.4 KB
7.0 KB
entry/src/main/resources/base/media/eye.svg
0 → 100644
| 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="1742787599186" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10839" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3-7.7 16.2-7.7 35.2 0 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766z" p-id="10840" fill="#ffffff"></path><path d="M508 336c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176z m0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z" p-id="10841" fill="#ffffff"></path></svg> |
| 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="1742787609097" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11050" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M955.733333 492.8c-6.4-12.8-162.133333-317.866667-443.733333-317.866667-23.466667 0-46.933333 2.133333-70.4 6.4-17.066667 4.266667-29.866667 19.2-25.6 36.266667 4.266667 17.066667 19.2 29.866667 36.266667 25.6 19.2-4.266667 38.4-4.266667 57.6-4.266667 209.066667 0 345.6 209.066667 379.733333 266.666667-10.666667 19.2-32 53.333333-64 91.733333-10.666667 12.8-8.533333 34.133333 4.266667 44.8 6.4 4.266667 12.8 6.4 21.333333 6.4s19.2-4.266667 25.6-10.666666c51.2-61.866667 78.933333-115.2 78.933333-117.333334 6.4-8.533333 6.4-19.2 0-27.733333zM215.466667 125.866667c-12.8-12.8-32-12.8-44.8 0-12.8 12.8-12.8 32 0 44.8l91.733333 91.733333C138.666667 354.133333 72.533333 484.266667 68.266667 490.666667c-4.266667 8.533333-4.266667 19.2 0 29.866666 6.4 12.8 162.133333 315.733333 443.733333 315.733334 83.2 0 164.266667-27.733333 241.066667-81.066667l96 96c6.4 6.4 14.933333 8.533333 23.466666 8.533333s17.066667-2.133333 23.466667-8.533333c12.8-12.8 12.8-32 0-44.8L215.466667 125.866667z m243.2 334.933333l104.533333 104.533333c-12.8 12.8-32 21.333333-51.2 21.333334-40.533333 0-74.666667-34.133333-74.666667-74.666667 0-19.2 8.533333-38.4 21.333334-51.2zM512 772.266667c-209.066667 0-345.6-209.066667-379.733333-266.666667 21.333333-36.266667 81.066667-130.133333 174.933333-196.266667l104.533333 104.533334c-25.6 25.6-38.4 59.733333-38.4 96 0 76.8 61.866667 138.666667 138.666667 138.666666 36.266667 0 70.4-14.933333 96-38.4l98.133333 98.133334c-61.866667 42.666667-128 64-194.133333 64z" fill="#ffffff" p-id="11051"></path></svg> |
| @@ -9,8 +9,28 @@ | @@ -9,8 +9,28 @@ | ||
| 9 | "value": "description" | 9 | "value": "description" |
| 10 | }, | 10 | }, |
| 11 | { | 11 | { |
| 12 | + "name": "EntryAbilityReadFile_desc", | ||
| 13 | + "value": "readFile" | ||
| 14 | + }, | ||
| 15 | + { | ||
| 16 | + "name": "EntryAbilityReadPhoto_desc", | ||
| 17 | + "value": "readPhoto" | ||
| 18 | + }, | ||
| 19 | + { | ||
| 20 | + "name": "EntryAbilitySharePlate_desc", | ||
| 21 | + "value": "readSharePlate" | ||
| 22 | + }, | ||
| 23 | + { | ||
| 24 | + "name": "EntryAbilityCamera_desc", | ||
| 25 | + "value": "Use your camera for video recording" | ||
| 26 | + }, | ||
| 27 | + { | ||
| 12 | "name": "EntryAbility_label", | 28 | "name": "EntryAbility_label", |
| 13 | - "value": "消防维保助手" | 29 | + "value": "Fire maintenance assistant" |
| 30 | + }, | ||
| 31 | + { | ||
| 32 | + "name": "video", | ||
| 33 | + "value": "Fire maintenance assistant for advertising" | ||
| 14 | } | 34 | } |
| 15 | ] | 35 | ] |
| 16 | } | 36 | } |
| @@ -9,20 +9,28 @@ | @@ -9,20 +9,28 @@ | ||
| 9 | "value": "description" | 9 | "value": "description" |
| 10 | }, | 10 | }, |
| 11 | { | 11 | { |
| 12 | - "name": "EntryAbility_label", | ||
| 13 | - "value": "消防维保助手" | ||
| 14 | - }, | ||
| 15 | - { | ||
| 16 | - "name": "EntryAbility1_desc", | 12 | + "name": "EntryAbilityReadFile_desc", |
| 17 | "value": "读取文件" | 13 | "value": "读取文件" |
| 18 | }, | 14 | }, |
| 19 | { | 15 | { |
| 20 | - "name": "EntryAbility2_desc", | 16 | + "name": "EntryAbilityReadPhoto_desc", |
| 21 | "value": "读取相册" | 17 | "value": "读取相册" |
| 22 | }, | 18 | }, |
| 23 | { | 19 | { |
| 24 | - "name": "EntryAbility3_desc", | 20 | + "name": "EntryAbilitySharePlate_desc", |
| 25 | "value": "读取剪切板" | 21 | "value": "读取剪切板" |
| 22 | + }, | ||
| 23 | + { | ||
| 24 | + "name": "EntryAbilityCamera_desc", | ||
| 25 | + "value": "使用相机拍照录像" | ||
| 26 | + }, | ||
| 27 | + { | ||
| 28 | + "name": "EntryAbility_label", | ||
| 29 | + "value": "消防维保助手" | ||
| 30 | + }, | ||
| 31 | + { | ||
| 32 | + "name": "video", | ||
| 33 | + "value": "消防维保助手广告" | ||
| 26 | } | 34 | } |
| 27 | ] | 35 | ] |
| 28 | } | 36 | } |
| @@ -19,6 +19,7 @@ | @@ -19,6 +19,7 @@ | ||
| 19 | "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", | 19 | "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", |
| 20 | "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19", | 20 | "@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19", |
| 21 | "@ohos/lottie@^2.0.9": "@ohos/lottie@2.0.16", | 21 | "@ohos/lottie@^2.0.9": "@ohos/lottie@2.0.16", |
| 22 | + "@ohos/videocompressor@^1.0.4": "@ohos/videocompressor@1.0.4", | ||
| 22 | "@wuyan/html_parse@^1.0.7": "@wuyan/html_parse@1.0.7", | 23 | "@wuyan/html_parse@^1.0.7": "@wuyan/html_parse@1.0.7", |
| 23 | "ksadsdk@entry/libs/KSAdSDK.har": "ksadsdk@entry/libs/KSAdSDK.har", | 24 | "ksadsdk@entry/libs/KSAdSDK.har": "ksadsdk@entry/libs/KSAdSDK.har", |
| 24 | "libapplogrs.so@oh_modules/.ohpm/@dp+applog@+e6gtiy4h3epopwj9muptqswanljuqcdrohmi055hmq=/oh_modules/@dp/applog/src/main/ets/types/libapplogrs": "libapplogrs.so@oh_modules/.ohpm/@dp+applog@+e6gtiy4h3epopwj9muptqswanljuqcdrohmi055hmq=/oh_modules/@dp/applog/src/main/ets/types/libapplogrs", | 25 | "libapplogrs.so@oh_modules/.ohpm/@dp+applog@+e6gtiy4h3epopwj9muptqswanljuqcdrohmi055hmq=/oh_modules/@dp/applog/src/main/ets/types/libapplogrs": "libapplogrs.so@oh_modules/.ohpm/@dp+applog@+e6gtiy4h3epopwj9muptqswanljuqcdrohmi055hmq=/oh_modules/@dp/applog/src/main/ets/types/libapplogrs", |
| @@ -139,6 +140,13 @@ | @@ -139,6 +140,13 @@ | ||
| 139 | "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/lottie/-/lottie-2.0.16.har", | 140 | "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/lottie/-/lottie-2.0.16.har", |
| 140 | "registryType": "ohpm" | 141 | "registryType": "ohpm" |
| 141 | }, | 142 | }, |
| 143 | + "@ohos/videocompressor@1.0.4": { | ||
| 144 | + "name": "@ohos/videocompressor", | ||
| 145 | + "version": "1.0.4", | ||
| 146 | + "integrity": "sha512-NGQOgKK81plBt7sfe314sp0U1B+r4eheYnsNI4CWG4PkJU6o4rU4lEGVDQ/wF/42RGYkwNw8A+tr26qXoX3kGQ==", | ||
| 147 | + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/videocompressor/-/videocompressor-1.0.4.har", | ||
| 148 | + "registryType": "ohpm" | ||
| 149 | + }, | ||
| 142 | "@wuyan/html_parse@1.0.7": { | 150 | "@wuyan/html_parse@1.0.7": { |
| 143 | "name": "@wuyan/html_parse", | 151 | "name": "@wuyan/html_parse", |
| 144 | "version": "1.0.7", | 152 | "version": "1.0.7", |
| @@ -9,7 +9,8 @@ | @@ -9,7 +9,8 @@ | ||
| 9 | "@csj/adapter_gdt": "^1.0.0-2", | 9 | "@csj/adapter_gdt": "^1.0.0-2", |
| 10 | "@csj/adapter_ks": "^2.0.3-beta-2", | 10 | "@csj/adapter_ks": "^2.0.3-beta-2", |
| 11 | "ksadsdk": "file:./entry/libs/KSAdSDK.har", | 11 | "ksadsdk": "file:./entry/libs/KSAdSDK.har", |
| 12 | - "@gdt/gdt-union-sdk": "file:./entry/libs/GDTUnionSDK-default-release.har" | 12 | + "@gdt/gdt-union-sdk": "file:./entry/libs/GDTUnionSDK-default-release.har", |
| 13 | + "@ohos/videocompressor": "^1.0.4" | ||
| 13 | }, | 14 | }, |
| 14 | "devDependencies": { | 15 | "devDependencies": { |
| 15 | "@ohos/hypium": "1.0.19", | 16 | "@ohos/hypium": "1.0.19", |
-
请 注册 或 登录 后发表评论