作者 xiaoqiu

添加了自定义视频录制功能

正在显示 39 个修改的文件 包含 1172 行增加217 行删除
不能预览此文件类型
... ... @@ -3,7 +3,7 @@
"bundleName": "com.example.fireMaintenanceAssistant",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"versionName": "1.0.1",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
... ...
不能预览此文件类型
不能预览此文件类型
... ... @@ -273,6 +273,7 @@ export interface ItemList {
proportion: string;
state: string;
record: recordType;
cosKey: string | null;
}
export interface recordType {
... ...
... ... @@ -10,6 +10,8 @@ export default struct AddPersonDialog {
personName: '',
idNo: ''
}
//确认添加后的回调
onChange: () => void = () => {}
build() {
Column(){
Text('添加人员').margin({top: 20})
... ... @@ -40,6 +42,7 @@ export default struct AddPersonDialog {
.onClick(async () => {
const res: AxiosResponse<beanType> = await companyAdd(this.addForm)
promptAction.showToast({message: res.data.msg})
this.onChange()
this.controller.close()
})
}
... ...
... ... @@ -14,7 +14,7 @@ import { PrintBiddingTokenUtils } from '../mediation_adtype/test/PrintBiddintTok
import { window, promptAction, router } from '@kit.ArkUI'
import { DemoConstants } from '../entryability/DemoConstants'
import('./SplashAdShowPage')
import('./CreateCamera')
@Builder
function bottomViewBuilder() {
... ... @@ -111,7 +111,13 @@ export struct SplashAdDemoPage {
build() {
Column() {
Image($r('app.media.logo')).width(60).height(60)
Stack(){
Progress({ value: 0, total: 10, type: ProgressType.Ring })
.width(120).color('#409EFF').backgroundColor('#fff')
.style({ strokeWidth: 10, status: ProgressStatus.LOADING })
Image($r('app.media.logo')).width(60).height(60)
}
}.width('100%').height('100%').justifyContent(FlexAlign.Center)
}
... ...
... ... @@ -496,9 +496,6 @@ struct EditUser {
}
pageTransition() {
// 该页面进入动画时长为1000ms,尽量与另一页面的退出动画时长匹配
PageTransitionEnter({ duration: 500 })
.slide(SlideEffect.Left).opacity(0)
// 该页面退出动画时长为1200ms,尽量与另一页面的进入动画时长匹配
PageTransitionExit({ duration: 500 })
.translate({ x: 150.0 })
... ...
import camera from '@ohos.multimedia.camera';
import media from '@ohos.multimedia.media';
import { BusinessError } from '@ohos.base';
import { promptAction, router } from '@kit.ArkUI'
import { common } from '@kit.AbilityKit';
import { FileUtil, CommonConstants } from '../utils/FileUtil';
import { uploadFileByTask } from '../utils/uploadCloud'
/**
* 视频录制
*/
interface routerParams {
cosKeyStr: string;
relateId: number;
}
const TAG: string = 'Record';
let context = getContext(this) as common.UIAbilityContext;
let routerParamsData: routerParams = router.getParams() as routerParams;
@Entry
@Component
struct CreateCamera {
@State xComponentWidth: number = 0;
@State xComponentHeight: number = 0;
@State recording: boolean = false;
@State path: string = '';
@State countTime: number = 0;
@State cameraManager: camera.CameraManager | undefined = undefined;
@State videoOutput: camera.VideoOutput | undefined = undefined;
@State captureSession: camera.Session | undefined = undefined;
@State cameraInput: camera.CameraInput | undefined = undefined;
@State previewOutput: camera.PreviewOutput | undefined = undefined;
@State avRecorder: media.AVRecorder | undefined = undefined;
private mXComponentController: XComponentController = new XComponentController;
private surfaceId: string = '';
url: string = '';
timer: number = 0;
aboutToAppear() {
// 创建存放视频文件
this.path = context.filesDir + '/' + 'VIDEO_' + Date.parse(new Date().toString()) + '.mp4';
let file = FileUtil.createOrOpen(this.path);
this.url = 'fd://' + file.fd;
}
build() {
Stack({ alignContent: Alignment.Top }) {
XComponent({
id: 'componentId',
type: XComponentType.SURFACE,
controller: this.mXComponentController,
})
.onLoad(async () => {
this.surfaceId = this.mXComponentController.getXComponentSurfaceId();
await this.initCamera(getContext(this), this.surfaceId);
})
.height(CommonConstants.SEVENTY_PERCENT)
.margin({
top: CommonConstants.FIFTEEN_PERCENT
})
Column() {
Text(`录制时长:${this.countTime}s`).fontSize(16).fontColor(Color.White)
Blank()
Row() {
Image(this.recording ? $r('app.media.camera_pause_video_4x') : $r('app.media.camera_take_video_4x'))
.width(px2vp(CommonConstants.IMAGE_SIZE))
.height(px2vp(CommonConstants.IMAGE_SIZE))
.onClick(async () => {
if (this.recording) {
clearInterval(this.timer);
this.timer = 0
await this.stopRecord();
await uploadFileByTask(routerParamsData.cosKeyStr, routerParamsData.relateId, this.path);
router.back()
} else {
this.timer = setInterval(async () => {
this.countTime++;
if(this.countTime >= 120){
clearInterval(this.timer);
this.timer = 0
await this.stopRecord();
await uploadFileByTask(routerParamsData.cosKeyStr, routerParamsData.relateId, this.path);
router.back()
}
}, 1000);
this.startRecord();
}
this.recording = !this.recording;
})
}
.width(CommonConstants.FULL_PERCENT)
.height(120)
.margin({ bottom: 60 })
.justifyContent(FlexAlign.Center)
.alignItems(VerticalAlign.Center)
}
.width(CommonConstants.FULL_PERCENT)
.height(CommonConstants.FULL_PERCENT)
.justifyContent(FlexAlign.Start)
.alignItems(HorizontalAlign.Start)
}
.backgroundColor(Color.Black)
.width(CommonConstants.FULL_PERCENT)
.height(CommonConstants.FULL_PERCENT)
}
// 初始化相机
async initCamera(context: common.Context, surfaceId: string) {
this.cameraManager = camera.getCameraManager(context);
if (!this.cameraManager) {
promptAction.showToast({ message: 'camera.getCameraManager error' })
return;
}
this.cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => {
promptAction.showToast({ message: `camera : ${cameraStatusInfo.camera.cameraId},status: ${cameraStatusInfo.status}` })
});
let cameraArray: Array<camera.CameraDevice> = [];
try {
cameraArray = this.cameraManager.getSupportedCameras();
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `getSupportedCameras call failed. error code: ${err.code}` })
}
if (cameraArray.length <= 0) {
promptAction.showToast({ message: 'cameraManager.getSupportedCameras error' })
return;
}
let cameraOutputCap: camera.CameraOutputCapability =
this.cameraManager.getSupportedOutputCapability(cameraArray[0], camera.SceneMode.NORMAL_VIDEO);
if (!cameraOutputCap) {
promptAction.showToast({ message: 'cameraManager.getSupportedOutputCapability error' })
return;
}
promptAction.showToast({ message: 'outputCapability: ' + JSON.stringify(cameraOutputCap) })
let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles;
if (!previewProfilesArray) {
promptAction.showToast({ message: 'createOutput previewProfilesArray === null || undefined' })
}
let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles;
if (!photoProfilesArray) {
promptAction.showToast({ message: 'createOutput photoProfilesArray === null || undefined' })
}
let videoProfilesArray: Array<camera.VideoProfile> = cameraOutputCap.videoProfiles;
if (!videoProfilesArray) {
promptAction.showToast({ message: 'createOutput videoProfilesArray === null || undefined' })
}
let videoSize: camera.Size = {
width: 640,
height: 480
}
let videoProfile: undefined | camera.VideoProfile = videoProfilesArray.find((profile: camera.VideoProfile) => {
return profile.size.width === videoSize.width && profile.size.height === videoSize.height;
});
if (!videoProfile) {
promptAction.showToast({ message: 'videoProfile is not found' })
return;
}
let aVRecorderProfile: media.AVRecorderProfile = {
audioBitrate: 48000,
audioChannels: 2,
audioCodec: media.CodecMimeType.AUDIO_AAC,
audioSampleRate: 48000,
fileFormat: media.ContainerFormatType.CFT_MPEG_4,
videoBitrate: 2000000,
videoCodec: media.CodecMimeType.VIDEO_AVC,
videoFrameWidth: videoSize.width,
videoFrameHeight: videoSize.height,
videoFrameRate: 30
};
let aVRecorderConfig: media.AVRecorderConfig = {
audioSourceType: media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC,
videoSourceType: media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV,
profile: aVRecorderProfile,
url: this.url,
rotation: 0,
location: {
latitude: 30,
longitude: 130
}
};
try {
this.avRecorder = await media.createAVRecorder();
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `createAVRecorder call failed. error code: ${err.code}` })
}
if (this.avRecorder === undefined) {
return;
}
try {
await this.avRecorder.prepare(aVRecorderConfig);
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `prepare call failed. error code: ${err.code}` })
}
let videoSurfaceId: string | undefined = undefined;
try {
videoSurfaceId = await this.avRecorder.getInputSurface();
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `getInputSurface call failed. error code: ${err.code}` })
}
if (videoSurfaceId === undefined) {
return;
}
try {
this.videoOutput = this.cameraManager.createVideoOutput(videoProfile, videoSurfaceId);
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to create the videoOutput instance. error: ${JSON.stringify(err)}` })
}
if (this.videoOutput === undefined) {
return;
}
this.videoOutput.on('frameStart', () => {
promptAction.showToast({ message: 'Video frame started' })
});
this.videoOutput.on('error', (error: BusinessError) => {
promptAction.showToast({ message: `Video frame error code: ${error.code}` })
});
try {
this.captureSession = this.cameraManager.createSession(camera.SceneMode.NORMAL_VIDEO) as camera.VideoSession;
;
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to create the CaptureSession instance. errorCode = ${err.code}` })
}
if (this.captureSession === undefined) {
return;
}
try {
this.captureSession.beginConfig();
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to beginConfig. errorCode = ${err.code}` })
}
let cameraInput: camera.CameraInput | undefined = undefined;
try {
cameraInput = this.cameraManager.createCameraInput(cameraArray[0]);
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to createCameraInput. errorCode = ${err.code}` })
}
if (cameraInput === undefined) {
return;
}
let cameraDevice: camera.CameraDevice = cameraArray[0];
cameraInput.on('error', cameraDevice, (error: BusinessError) => {
promptAction.showToast({ message: `Camera input error code: ${error.code}` })
});
try {
await cameraInput.open();
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to open cameraInput. errorCode = ${err.code}` })
}
try {
this.captureSession.addInput(cameraInput);
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to add cameraInput. errorCode = ${err.code}` })
}
let previewOutput: camera.PreviewOutput | undefined = undefined;
try {
previewOutput = this.cameraManager.createPreviewOutput(videoProfile, surfaceId);
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to create the previewOutput instance. error: ${JSON.stringify(err)}` })
}
if (previewOutput === undefined) {
return;
}
try {
this.captureSession.addOutput(previewOutput);
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to add previewOutput. errorCode = ${err.code}` })
}
try {
this.captureSession.addOutput(this.videoOutput);
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to add videoOutput. errorCode = ${err.code}` })
}
try {
await this.captureSession.commitConfig();
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to commitConfig. errorCode = ${err.code}` })
}
try {
await this.captureSession.start();
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `Failed to start captureSession. errorCode = ${err.code}` })
}
this.videoOutput.start((err: BusinessError) => {
if (err) {
promptAction.showToast({ message: `Failed to start the video output. error: ${JSON.stringify(err)}` })
return;
}
promptAction.showToast({message: 'Callback invoked to indicate the video output start success.'})
});
}
// 开始录像
async startRecord() {
if (this.avRecorder) {
try {
await this.avRecorder.start();
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `avRecorder start error: ${JSON.stringify(err)}` })
}
}
}
// 停止录像
async stopRecord() {
if (this.avRecorder) {
try {
if (this.videoOutput) {
this.videoOutput.stop((err: BusinessError) => {
if (err) {
promptAction.showToast({ message: `Failed to stop the video output. error: ${JSON.stringify(err)}` })
return;
}
promptAction.showToast({message: 'Callback invoked to indicate the video output stop success.'})
});
}
try {
await this.avRecorder.stop();
await this.avRecorder.release();
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `avRecorder stop error: ${JSON.stringify(err)}` })
}
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `avRecorder stop error: ${JSON.stringify(err)}` })
}
try {
if (this.captureSession) {
this.captureSession.stop();
}
if (this.cameraInput) {
this.cameraInput.close();
}
if (this.previewOutput) {
this.previewOutput.release();
}
if (this.videoOutput) {
this.videoOutput.release();
}
if (this.captureSession) {
this.captureSession.release();
}
if (this.captureSession) {
this.captureSession = undefined;
}
} catch (error) {
let err = error as BusinessError;
promptAction.showToast({ message: `avRecorder stop error: ${JSON.stringify(err)}` })
}
}
}
}
\ No newline at end of file
... ...
... ... @@ -3,19 +3,20 @@ import { pasteboard } from '@kit.BasicServicesKit';
import preferencesUtils from '../utils/preferences'
import { AxiosResponse } from '@ohos/axios'
import { HmParseHTML } from "@wuyan/html_parse"
import { BusinessError } from '@kit.BasicServicesKit';
import { uploadFileByTask, selectImgOrVideo } from '../utils/uploadCloud'
import { basePath } from '../utils/baseUrl'
import {getCloudDown, beanType} from '../api/user'
import loadingDialog from '../dialog/LoadingDialog'
import UploadTipDialog from '../dialog/UploadTipDialog'
import { getReportDetail, getMalfunctionList, deleteRecords, successReport, returnSing } from '../api/originalRecords'
import { reportDetailTest, reportDetailData, ProjectList, MalfunctionListTest, MalfunctionListRow, configTest } from '../api/recordsType'
import { reportDetailTest, reportDetailData, ProjectList, ItemList, MalfunctionListTest, MalfunctionListRow, configTest } from '../api/recordsType'
import { pushOutsideWeb } from '../utils/pushOutsideWeb'
import ThemeStaticTest from '../components/ThemeStaticText'
import NavHeader from '../components/NavHeader'
interface showVideoOrImg {
cosKey: string | null;
itemName: string;
}
interface routerParams {
reportId: number
}
... ... @@ -86,6 +87,10 @@ struct DetailRecords {
})
}
// 判断是否存在视频或图片
isImgOrVideo = (list: ItemList[]): boolean => {
return list.some(item => item.cosKey !== null)
}
build() {
Column(){
NavHeader({title: '维保记录详情'})
... ... @@ -235,20 +240,33 @@ struct DetailRecords {
Column({space: 5}){
Row(){
Row({space: 5}){
Text((index + 1).toString()).padding(10).borderRadius(5)
.backgroundColor(Color.Gray).fontSize('#666')
Text(item.projectName).fontSize(12).fontColor('#999')
Text((index + 1).toString()).width(40).height(40).borderRadius(5)
.backgroundColor('#eee').fontSize('#666').textAlign(TextAlign.Center)
Row(){
Text(item.projectName).fontSize(16).fontColor('#1890ff')
Image($r('app.media.edit_1')).width(16).margin({right: 4})
}.onClick(() => {
router.pushUrl({
url: 'pages/FireProtectionDetail',
params: item
})
})
}
Row(){
Text('查看视频/图片内容').fontSize(12).fontColor('#1890ff')
Image($r('app.media.right_arrow')).width(12)
}.visibility(this.isShowCloudDown && item.cosKey !== null ? Visibility.Visible : Visibility.None)
}.visibility(this.isImgOrVideo(item.itemList) ? Visibility.Visible : Visibility.None)
.onClick(() => {
const newArr: showVideoOrImg[] = item.itemList.map((item: ItemList): showVideoOrImg => {
return {
cosKey: item.cosKey,
itemName: item.itemName
}
})
router.pushUrl({
url: 'pages/VideoDetail',
params: {
cosKey: item.cosKey,
relateId: item.relateId
cosKeyList: newArr
}
})
})
... ... @@ -260,37 +278,6 @@ struct DetailRecords {
.borderWidth(1).fontSize(12).borderRadius(4).lineHeight(16).fontColor(item.state == '0' ? '#ff4949' : '#13ce66')
.backgroundColor(item.state == '0' ? '#ffeded' : '#e7faf0').borderColor(item.state == '0' ? '#ffdbdb' : '#d0f5e0')
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
Row(){
Row(){
Image($r('app.media.photo')).width(12).margin({right: 4})
Text('上传视频/图片').fontSize(12).fontColor('#1890ff')
}.layoutWeight(1).justifyContent(FlexAlign.Center)
.visibility(this.isShowCloudDown ? Visibility.Visible : Visibility.None)
.onClick(async () => {
// 上传文件到腾讯云存储
try {
let key: string = item.cosKey == null ? '' : item.cosKey
let systemPhotoImagePath: string = await selectImgOrVideo() // 选择文件
this.loadingController.open()
await uploadFileByTask(key, item.relateId, systemPhotoImagePath)
this.loadingController.close()
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
}
})
Text().width(2).height(16).backgroundColor('#eee').visibility(this.isShowCloudDown ? Visibility.Visible : Visibility.None)
Row(){
Image($r('app.media.edit_1')).width(12).margin({right: 4})
Text('编辑详情').fontSize(12).fontColor('#1890ff').onClick(() => {
router.pushUrl({
url: 'pages/FireProtectionDetail',
params: item
})
})
}.layoutWeight(1).justifyContent(FlexAlign.Center)
}.width('100%').padding({top: 5}).border({width: {top: 1}, color: '#eee'})
.visibility(item.state == '0' ? Visibility.Visible : Visibility.None)
}.padding({top: 10, left: 10, right: 10, bottom: 10}).borderWidth(1).borderColor('#eee').shadow({ radius: 5, color: Color.Gray }).borderRadius(5)
})
}.backgroundColor('#fff').borderRadius(10).padding(10).width('100%')
... ... @@ -500,9 +487,6 @@ struct DetailRecords {
pageTransition() {
// 该页面进入动画时长为1000ms,尽量与另一页面的退出动画时长匹配
PageTransitionEnter({ duration: 500 })
.slide(SlideEffect.Left).opacity(0)
// 该页面退出动画时长为1200ms,尽量与另一页面的进入动画时长匹配
PageTransitionExit({ duration: 500 })
.translate({ x: 150.0 })
... ...
import { router } from '@kit.ArkUI'
import { router, promptAction } from '@kit.ArkUI'
import { ProjectList } from '../api/recordsType'
import { webview } from '@kit.ArkWeb'
import { basePath } from '../utils/baseUrl'
import fs from '@ohos.file.fs';
import preferencesUtils from '../utils/preferences'
import { BusinessError, request } from '@kit.BasicServicesKit';
import { cameraPickerImg, cameraPickerVideo, videoCompressMethod } from '../utils/uploadFile'
import { getCosKey, cosKeyTest, cosKeyData, uploadVideoOrImg } from '../api/cosKey'
import loadingDialog from '../dialog/LoadingDialog'
import { rpc } from '@kit.IPCKit';
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { AxiosResponse } from '@ohos/axios'
let routerInfo: ProjectList = router.getParams() as ProjectList
const context = getContext() as common.UIAbilityContext;
@Entry
@Component
... ... @@ -11,13 +21,161 @@ struct FireProtectionDetail {
controller: RichEditorController = new RichEditorController();
options: RichEditorOptions = { controller: this.controller };
@State projectInfo: ProjectList = routerInfo
private result: boolean = false;
permissions: Array<Permissions> = [
'ohos.permission.CAMERA',
'ohos.permission.MICROPHONE',
'ohos.permission.MEDIA_LOCATION'
];
webviewController: webview.WebviewController = new webview.WebviewController()
aboutToAppear(): void {
this.reqPermissionsFromUser(this.permissions, context)
}
// 加载弹窗
loadingController: CustomDialogController = new CustomDialogController({
builder: loadingDialog(),
customStyle: true,
offset: { dx: 0, dy: 0 },
alignment: DialogAlignment.Center,
autoCancel: false
})
// 获取用户授权
reqPermissionsFromUser(permissions: Array<Permissions>, context: common.UIAbilityContext) {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
atManager.requestPermissionsFromUser(context, permissions).then((data) => {
let grantStatus: Array<number> = data.authResults;
let length: number = grantStatus.length;
for (let i = 0; i < length; i++) {
if (grantStatus[i] === 0) {
promptAction.showToast({message: 'User authorized.'})
} else {
promptAction.showToast({message: 'User denied authorization.'})
return;
}
}
}).catch((err: BusinessError) => {
promptAction.showToast({message: `Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`})
})
}
// 检查用户是否授权
checkAccessToken(permissions: Array<Permissions>) {
// Determine the authorization status.
let callerTokenId: number = rpc.IPCSkeleton.getCallingTokenId();
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
try {
for (let i = 0; i < permissions.length; i++) {
let data: abilityAccessCtrl.GrantStatus = atManager.verifyAccessTokenSync(callerTokenId, permissions[i]);
if (data === -1) {
this.result = false;
} else {
this.result = true;
}
if (!this.result) {
break;
}
}
} catch (err) {
promptAction.showToast({message: `checkAccessToken catch err->${JSON.stringify(err)}`})
}
}
// 上传方法
uploadMethods = async (cosKeyStr: string | null, relateId: number, systemPhotoImagePath: string, fileType: string) => {
let _this = this
_this.loadingController.open()
let cacheDir = getContext().cacheDir // 获取缓存目录
let filetype = fileType // 设置文件类型
let filename = Date.now() + '.' + filetype // 设置文件名称
let fullPath = cacheDir + '/' + filename // 设置文件路径
const file = fs.openSync(systemPhotoImagePath, fs.OpenMode.READ_ONLY) // 打开文件
fs.copyFileSync(file.fd, fullPath) // 复制文件
// 获取直传签名等数据
let directTransferResult: AxiosResponse<cosKeyTest> = await getCosKey(filename);
let directTransferData: cosKeyData = directTransferResult.data.data
if (directTransferData == null) {
promptAction.showToast({ message: 'getStsDirectSign fail' });
return;
}
let cosKey = directTransferData.coskey
// 生成上传的url
let url = directTransferData.preSignedUrl
// 开始上传
try {
let uploadTask = await request.uploadFile(getContext(),{ // 上传图片
url: url, // 请求地址
// 请求头
header:{
"Content-Type": "application/octet-stream"
},
method: "PUT",
files:[{ // 上传文件
filename: filename, // 文件名
type: 'jpg', // 文件扩展名
name:'file', // 接口参数名
uri:`internal://cache/${filename}` // 缓存目录中的要上传给服务器的图片路径
}],
data:[]
})
// 上传成功
uploadTask.on('complete', async (taskStates: Array<request.TaskState>) => {
_this.loadingController.close()
for (let i = 0; i < taskStates.length; i++) {
let cosKeyArr: string[] = []
if(cosKeyStr !== null) {
cosKeyArr = cosKeyStr.split(';')
}
cosKeyArr.push(cosKey)
console.log('最终的cosKeys数据: ' + cosKeyArr.join(';'))
await uploadVideoOrImg({ cosKey: cosKeyArr.join(';'), relateId: relateId })
await _this.webviewController.runJavaScript(`window.setKey(${JSON.stringify(cosKeyArr.join(';'))})`)
_this.loadingController.close()
}
});
// 上传失败
uploadTask.on('fail', (taskStates: Array<request.TaskState>) => {
_this.loadingController.close()
for (let i = 0; i < taskStates.length; i++) {
promptAction.showToast({ message: '上传失败' });
_this.loadingController.close()
}
});
} catch (error) {
let err: BusinessError = error as BusinessError;
console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`);
return error
}
}
build() {
Column(){
Web({
src: `${basePath}/report/handle?id=${this.projectInfo.reportId}&pid=${this.projectInfo.projectId}&token=${preferencesUtils.get('XF_TOKEN', '')}`,
src: `${basePath}/report/handle?id=${this.projectInfo.reportId}&pid=${this.projectInfo.projectId}&source=harmony&token=${preferencesUtils.get('XF_TOKEN', '')}`,
// src: 'http://www.xiao-ming.love/',
controller: this.webviewController,
}).mixedMode(MixedMode.All).javaScriptAccess(true).domStorageAccess(true)
.onConsole((event) => {
let data = event.message.getMessage().replace(/^['"]|['"]$/g, '');
let formatData = data.split('&')
let cosKeyStr: string | null = formatData[1]
let relateId: number = parseInt(formatData[2])
if (formatData[0] == '鸿蒙图片上传') {
// 使用相机拍照
cameraPickerImg().then(async systemPhotoImagePath => {
if (systemPhotoImagePath == '' || systemPhotoImagePath == null) {
return promptAction.showToast({ message: '用户取消选择' });
}
this.uploadMethods(cosKeyStr, relateId, systemPhotoImagePath, 'jpg')
})
} else if(formatData[0] == '鸿蒙视频上传'){
// 使用相机录像
this.checkAccessToken(this.permissions);
if (this.result) {
router.pushUrl({ url: 'pages/CreateCamera', params: { cosKeyStr: cosKeyStr, relateId: relateId} })
}
}
return false
})
}.height('100%').width('100%')
}
}
\ No newline at end of file
... ...
... ... @@ -38,25 +38,26 @@ struct Login {
build() {
Column(){
Column({space: 20}){
Image($r('app.media.logo')).width(100).borderRadius(22)
Text('消防维保助手').fontSize(30).fontWeight(500).fontColor('#fff')
}.margin({top: 50, bottom: 50})
Column(){
Image($r('app.media.logo')).width(100).borderRadius(22).margin({bottom: 20})
Text('消防维保助手').fontSize(30).fontWeight(500).fontColor('#fff').margin({bottom: 5})
Text('鸿蒙专版').fontSize(14).fontColor(Color.White).fontWeight(500)
}.margin({top: 50, bottom: 30})
Column({space:10}){
Row(){
Image($r('app.media.account')).width(20)
TextInput({text: $$this.loginForm.username, placeholder: '请填写用户名'})
.backgroundColor(Color.Transparent).fontColor('#fff').fontSize(14)
.backgroundColor(Color.Transparent).fontColor('#fff').fontSize(16)
.borderRadius(0).layoutWeight(1).placeholderColor('#fff')
}.width('100%').border({width:{bottom: 1}, color: '#eee'})
Row(){
Image($r('app.media.password')).width(20)
TextInput({text: $$this.loginForm.password, placeholder: '请填写密码'}).type(InputType.Password)
.backgroundColor(Color.Transparent).fontColor('#fff').fontSize(14)
TextInput({text: $$this.loginForm.password, placeholder: '请填写密码'})
.backgroundColor(Color.Transparent).fontColor('#fff').fontSize(16)
.borderRadius(0).layoutWeight(1).placeholderColor('#fff')
}.width('100%').border({width:{bottom: 1}, color: '#eee'})
}.margin({bottom: 10}).padding({left: 10, right: 10})
}.margin({bottom: 10}).padding({left: 20, right: 20})
Column({space: 10}){
Row({space: 5}){
Checkbox({group: 'user' })
... ... @@ -112,7 +113,7 @@ struct Login {
})
Text('记住密码').fontSize(12).fontColor('#fff')
}.width('100%').justifyContent(FlexAlign.Start)
}.alignItems(HorizontalAlign.Start).padding({left: 10, right: 10})
}.alignItems(HorizontalAlign.Start).padding({left: 20, right: 20})
Button('立即登录')
.width('80%').height(40)
... ... @@ -155,7 +156,7 @@ struct Login {
preferencesUtil.set('XF_PERSON_ID', personInfo.data.data.personId)
preferencesUtil.set('XF_USERNAME', personInfo.data.data.username)
}
router.replaceUrl({
router.pushUrl({
url: 'pages/Index'
})
})
... ...
... ... @@ -17,7 +17,8 @@ struct LookRecords {
build() {
Column(){
Web({
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', '')}`,
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', '')}`,
controller: this.webviewController,
}).mixedMode(MixedMode.All).javaScriptAccess(true).domStorageAccess(true)
}.width('100%').height('100%').backgroundColor('#f2f3f7')
... ...
... ... @@ -35,7 +35,12 @@ let getTextInfo = (state: string | null) => {
@Component
struct PersonList {
dialogController: CustomDialogController = new CustomDialogController({
builder: AddPersonDialog(),
builder: AddPersonDialog({
// 确认添加后的回调
onChange: () => {
this.getList()
}
}),
cornerRadius: 10
})
@State params: QueryParams = {
... ...
import { webview } from '@kit.ArkWeb'
import NavHeader from '../components/NavHeader'
@Entry
@Component
struct FireProtectionDetail {
webviewController: webview.WebviewController = new webview.WebviewController()
build() {
Column(){
NavHeader({title: '隐私政策'})
Web({
src: `https://doc.crgx.net/privacy.html`,
controller: this.webviewController,
... ...
import { CSJSplashAd } from '@csj/openadsdk';
import { NodeController, window } from '@kit.ArkUI';
@Entry({
routeName: "GMSplashAdShowPage",
storage: LocalStorage.getShared()
})
@Component
export struct SplashAdShowPage {
@LocalStorageLink('GMSplashAd') splashAd: CSJSplashAd | undefined = undefined
@LocalStorageLink('GMSplashSubWindow') _window: window.Window | undefined = undefined
@LocalStorageProp('GMSplashCustomCloseBtn') splashCustomCloseBtn: boolean = false
@State splashAdComponent: NodeController | undefined = undefined
aboutToAppear(): void {
this.splashAdComponent = this.splashAd?.getAdComponent(this.splashCustomCloseBtn, this._window)
}
onPageShow(): void {
this._window?.setWindowLayoutFullScreen(true)
}
onPageHide(): void {
this._window?.setWindowLayoutFullScreen(false)
}
build() {
Stack() {
if (this.splashAdComponent) {
NodeContainer(this.splashAdComponent)
}
if (this.splashCustomCloseBtn) {
Text('close')
.textAlign(TextAlign.Center)
.backgroundColor(Color.Yellow)
.width(60)
.height(60)
.borderRadius(30)
.margin({ left: 50, top: 50 })
.onClick(() => {
this.closeBtnClicked()
})
}
}
.alignContent(Alignment.TopStart)
}
closeBtnClicked() {
this._window?.destroyWindow()
}
}
\ No newline at end of file
... ... @@ -26,7 +26,7 @@ struct StartAd {
const result = await CSJAdSdk.start()
if (result) {
if (result.code == 0 || result.code == 4200) {
router.pushUrl({ url: 'pages/AdMainPage' })
router.replaceUrl({ url: 'pages/AdMainPage' })
// this.loadOpenAd()
} else {
promptAction.showToast({ message: result.msg });
... ... @@ -41,7 +41,13 @@ struct StartAd {
build() {
Column() {
Image($r('app.media.logo')).width(60).height(60)
Stack(){
Progress({ value: 0, total: 10, type: ProgressType.Ring })
.width(120).color('#409EFF').backgroundColor('#fff')
.style({ strokeWidth: 10, status: ProgressStatus.LOADING })
Image($r('app.media.logo')).width(60).height(60)
}
}.width('100%').height('100%').justifyContent(FlexAlign.Center)
}
}
\ No newline at end of file
... ...
... ... @@ -4,17 +4,25 @@ import { downFile } from '../utils/downFile'
import { router } from '@kit.ArkUI'
import PhotoBrowser from '../dialog/PhotoBrowserDialog'
import NavHeader from '../components/NavHeader'
interface showVideoOrImg {
cosKey: string | null;
itemName: string;
videoList?: string[];
imgList?: string[];
}
interface VideoOrImgList {
videoList: string[];
imgList: string[];
}
interface routerParams {
cosKey: string
relateId: number
cosKeyList: showVideoOrImg[]
}
let routerQuery = router.getParams() as routerParams
@Entry
@Component
struct DownLoadImage {
@State imgList: string[] = []
@State videoList: string[] = []
@State cosKeyData: string[] = routerQuery?.cosKey.split(';')
@State cosKeyData: showVideoOrImg[] = routerQuery?.cosKeyList
@State showCosKeyList: showVideoOrImg[] = []
@State viewImg: string[] = []
@State viewVideo: string[] = []
@State saveButtonOptions: SaveButtonOptions = {
... ... @@ -28,100 +36,111 @@ struct DownLoadImage {
offset: { dx: 0, dy: 0 },
alignment: DialogAlignment.Top,
})
aboutToAppear() {
this.cosKeyData.forEach((item: string) => {
let newArr = item.split('.')
let index = newArr.length - 1
if(newArr[index] == 'mp4') {
this.videoList.push(item)
}else {
this.imgList.push(item)
async aboutToAppear() {
this.showCosKeyList = await Promise.all(this.cosKeyData.map(async (item: showVideoOrImg) => {
if (item.cosKey) {
const arrList: VideoOrImgList | [] = await this.getVideoOrImgUrl(item.cosKey)
if (!Array.isArray(arrList)) {
item.videoList = arrList.videoList
item.imgList = arrList.imgList
}
}
return item
}))
}
// 请求获取图片或视频链接
getVideoOrImgUrl = async (cosKey: string | null) => {
let result: VideoOrImgList | [] = this.filterVideoOrImg(cosKey)
if (!Array.isArray(result)) {
let videoData: string[] = await Promise.all(result.videoList.map(async (item: string) => {
const res: AxiosResponse<downloadUrl> = await getDownloadUrl(item, 0)
return res.data.data
}))
let imgData: string[] = await Promise.all(result.imgList.map(async (item: string) => {
const res: AxiosResponse<downloadUrl> = await getDownloadUrl(item, 0)
return res.data.data
}))
result = {
videoList: videoData,
imgList: imgData
}
}
return result
}
// 筛选图片或者视频
filterVideoOrImg = (cosKey: string | null): VideoOrImgList | [] => {
let urlList: string[] | undefined = cosKey?.split(';')
let videoList: string[] = []
let imgList: string[] = []
if(urlList === undefined) return []
urlList.forEach((item: string) => {
let newItemList: string[] = item.split('.')
if(newItemList[newItemList.length - 1] == 'mp4' || newItemList[newItemList.length - 1] == 'mkv'){
videoList.push(item)
} else {
imgList.push(item)
}
})
this.imgList.forEach(async (item: string) => {
const imgDta: AxiosResponse<downloadUrl> = await getDownloadUrl(item, 0)
this.viewImg.push(imgDta.data.data)
})
this.videoList.forEach(async (item: string) => {
const imgDta: AxiosResponse<downloadUrl> = await getDownloadUrl(item, 0)
this.viewVideo.push(imgDta.data.data)
})
return {
videoList,
imgList
}
}
build() {
Column(){
NavHeader({title: '下载图片'})
NavHeader({title: '视频/图片下载'})
List(){
ListItem(){
Column({ space: 10 }) {
Row(){
ForEach(this.showCosKeyList, (item:showVideoOrImg ) => {
ListItem(){
Column({ space: 10 }) {
Row({space: 5}){
Text().width(2).height(20).backgroundColor('#1890ff')
Text('图片').fontSize(14).fontWeight(600)
}
Text('预览图片')
.fontSize(14).fontColor('#fff').backgroundColor('#1890ff')
.padding({left: 15, right: 15, top: 2, bottom: 2})
.borderRadius(4)
.onClick(() => {
this.photoBrowserController.open()
Text(item.itemName).fontSize(14).fontWeight(600)
}.width('100%')
GridRow({ columns: 2, gutter: 10 }) {
ForEach(item.imgList, (childrenImg: string) => {
GridCol() {
Column({space: 10}){
Image(childrenImg)
.width('100%')
.height(150)
.borderRadius(4)
Row(){
SaveButton(this.saveButtonOptions)
// 创建安全控件按钮
.onClick(async (event, result: SaveButtonOnClickResult) => {
if (result == SaveButtonOnClickResult.SUCCESS) {
downFile(childrenImg, 'jpg')
}
})
}
}
}
})
}
.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
GridRow({ columns: 2, gutter: 10 }) {
ForEach(this.viewImg, (item: string) => {
GridCol() {
Column({space: 10}){
Image(item)
.width('100%')
.height(150)
.borderRadius(4)
Row(){
}
GridRow({ columns: 1}) {
ForEach(item.videoList, (childrenVideo: string) => {
GridCol() {
Column({ space: 10}){
Video({ src: childrenVideo }).width('100%').height(300)
SaveButton(this.saveButtonOptions)
// 创建安全控件按钮
.onClick(async (event, result: SaveButtonOnClickResult) => {
if (result == SaveButtonOnClickResult.SUCCESS) {
downFile(item, 'jpg')
downFile(childrenVideo, 'mp4')
}
})
}
}
}
})
}
}
}.visibility(this.viewImg.length == 0 ? Visibility.None : Visibility.Visible)
ListItem(){
Column({ space: 10 }) {
Row(){
Row({space: 5}){
Text().width(2).height(20).backgroundColor('#1890ff')
Text('视频').fontSize(14).fontWeight(600)
}
}
.justifyContent(FlexAlign.Start)
.width('100%')
GridRow({ columns: 1}) {
ForEach(this.viewVideo, (item: string) => {
GridCol() {
Column({ space: 10}){
Video({ src: item }).width('100%').height(300).controls(true)
SaveButton(this.saveButtonOptions)
// 创建安全控件按钮
.onClick(async (event, result: SaveButtonOnClickResult) => {
if (result == SaveButtonOnClickResult.SUCCESS) {
downFile(item, 'mp4')
}
})
}
}
.margin({
top: 10
}.margin({ top: 10 })
})
})
}
}
}
}.visibility(this.viewVideo.length == 0 ? Visibility.None : Visibility.Visible)
})
}.padding(10)
}
}
... ...
import { media } from '@kit.MediaKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { fileIo as fs, fileUri } from '@kit.CoreFileKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
const TAG = 'VideoRecorderDemo:';
export class VideoRecorderDemo {
private context: Context;
constructor() {
this.context = getContext(this);
}
private avRecorder: media.AVRecorder | undefined = undefined;
private videoOutSurfaceId: string = "";
private avProfile: media.AVRecorderProfile = {
fileFormat : media.ContainerFormatType.CFT_MPEG_4, // 视频文件封装格式,只支持MP4
videoBitrate : 100000, // 视频比特率
videoCodec : media.CodecMimeType.VIDEO_AVC, // 视频文件编码格式,支持avc格式
videoFrameWidth : 640, // 视频分辨率的宽
videoFrameHeight : 480, // 视频分辨率的高
videoFrameRate : 30 // 视频帧率
};
private avConfig: media.AVRecorderConfig = {
videoSourceType : media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, // 视频源类型,支持YUV和ES两种格式
profile : this.avProfile,
url : 'fd://35', // 参考应用文件访问与管理开发示例新建并读写一个文件
rotation : 0 // 视频旋转角度,默认为0不旋转,支持的值为0、90、180、270
};
private uriPath: string = ''; // 文件uri,可用于安全控件保存媒体资源
private filePath: string = ''; // 文件路径
private fileFd: number = 0;
// 创建文件以及设置avConfig.url
async createAndSetFd() {
const path: string = this.context.filesDir + '/example.mp4'; // 文件沙箱路径,文件后缀名应与封装格式对应
const videoFile: fs.File = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
this.avConfig.url = 'fd://' + videoFile.fd; // 设置url
this.fileFd = videoFile.fd; // 文件fd
this.filePath = path;
}
// 注册avRecorder回调函数
setAvRecorderCallback() {
if (this.avRecorder != undefined) {
// 状态机变化回调函数
this.avRecorder.on('stateChange', (state: media.AVRecorderState, reason: media.StateChangeReason) => {
console.info(TAG + 'current state is: ' + state);
})
// 错误上报回调函数
this.avRecorder.on('error', (err: BusinessError) => {
console.error(TAG + 'error ocConstantSourceNode, error message is ' + err);
})
}
}
// 相机相关准备工作
async prepareCamera() {
// 具体实现查看相机资料
}
// 启动相机出流
async startCameraOutput() {
// 调用VideoOutput的start接口开始录像输出
}
// 停止相机出流
async stopCameraOutput() {
// 调用VideoOutput的stop接口停止录像输出
}
// 释放相机实例
async releaseCamera() {
// 释放相机准备阶段创建出的实例
}
// 开始录制对应的流程
async startRecordingProcess() {
if (this.avRecorder === undefined) {
// 1.创建录制实例;
this.avRecorder = await media.createAVRecorder();
this.setAvRecorderCallback();
}
// 2. 获取录制文件fd;获取到的值传递给avConfig里的url,实现略
// 3.配置录制参数完成准备工作
await this.avRecorder.prepare(this.avConfig);
this.videoOutSurfaceId = await this.avRecorder.getInputSurface();
// 4.完成相机相关准备工作
await this.prepareCamera();
// 5.启动相机出流
await this.startCameraOutput();
// 6. 启动录制
await this.avRecorder.start();
}
// 暂停录制对应的流程
async pauseRecordingProcess() {
if (this.avRecorder != undefined && this.avRecorder.state === 'started') { // 仅在started状态下调用pause为合理状态切换
await this.avRecorder.pause();
await this.stopCameraOutput(); // 停止相机出流
}
}
// 恢复录制对应的流程
async resumeRecordingProcess() {
if (this.avRecorder != undefined && this.avRecorder.state === 'paused') { // 仅在paused状态下调用resume为合理状态切换
await this.startCameraOutput(); // 启动相机出流
await this.avRecorder.resume();
}
}
async stopRecordingProcess() {
if (this.avRecorder != undefined) {
// 1. 停止录制
if (this.avRecorder.state === 'started'
|| this.avRecorder.state === 'paused' ) { // 仅在started或者paused状态下调用stop为合理状态切换
await this.avRecorder.stop();
await this.stopCameraOutput();
}
// 2.重置
await this.avRecorder.reset();
// 3.释放录制实例
await this.avRecorder.release();
// 4.文件录制完成后,关闭fd,实现略
await fs.close(this.fileFd);
// 5.释放相机相关实例
await this.releaseCamera();
}
}
// 安全控件保存媒体资源至图库
async saveRecorderAsset() {
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context);
// 需要确保uriPath对应的资源存在
this.uriPath = fileUri.getUriFromPath(this.filePath); // 获取录制文件的uri,用于安全控件保存至图库
let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest =
photoAccessHelper.MediaAssetChangeRequest.createVideoAssetRequest(this.context, this.uriPath);
await phAccessHelper.applyChanges(assetChangeRequest);
}
// 一个完整的【开始录制-暂停录制-恢复录制-停止录制】示例
async videoRecorderDemo() {
await this.startRecordingProcess(); // 开始录制
// 用户此处可以自行设置录制时长,例如通过设置休眠阻止代码执行
await this.pauseRecordingProcess(); //暂停录制
await this.resumeRecordingProcess(); // 恢复录制
await this.stopRecordingProcess(); // 停止录制
// 安全控件保存媒体资源至图库
await this.saveRecorderAsset();
}
}
\ No newline at end of file
... ...
import fs from '@ohos.file.fs';
import buffer from '@ohos.buffer';
// 大小和单位
const GB_MAGNITUDE: number = 1024 * 1024 * 1024
const MB_MAGNITUDE: number = 1024 * 1024
const KB_MAGNITUDE: number = 1024
const GB_SYMBOL: string = 'GB'
const MB_SYMBOL: string = 'MB'
const KB_SYMBOL: string = 'KB'
const BYTE_SYMBOL: string = 'B'
export class FileUtil {
/**
* 新建并打开文件
*/
static createOrOpen(path: string) : fs.File{
let isExist = fs.accessSync(path);
let file: fs.File;
if(isExist) {
file = fs.openSync(path, fs.OpenMode.READ_WRITE);
}else {
file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
}
return file;
}
/**
* 保存arrayBuffer到文件
* @param path
* @param arrayBuffer
* @returns
*/
static writeBufferToFile(path: string, arrayBuffer: ArrayBuffer): number {
try {
let file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let value = fs.writeSync(file.fd, arrayBuffer);
fs.closeSync(file);
return value;
}catch (err){
console.log("FileUtil", "writeFile err:" + err);
return -1;
}
}
/**
* 保存文本到文件
* @param path
* @param text
* @returns
*/
static writeStrToFile(path: string, text: string): number {
try {
let file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let value = fs.writeSync(file.fd, text);
fs.closeSync(file);
return value;
}catch (err) {
console.log("FileUtil", "writeFile err:" + err);
return -1;
}
}
}
export class CommonConstants {
/**
* ShowToast duration.
*/
static readonly SHOW_TOAST_DURATION: number = 4000;
/**
* ShowToast bottom.
*/
static readonly SHOW_TOAST_BOTTOM: number = 108;
/**
* Image size.
*/
static readonly IMAGE_SIZE: number = 200;
/**
* The full percentage of component.
*/
static readonly FULL_PERCENT: string = '100%';
/**
* The ninety percent of the components.
*/
static readonly NINETY_PERCENT: string = '90%';
/**
* The seventy percent of the components.
*/
static readonly SEVENTY_PERCENT: string = '70%';
/**
* The fifteen percent of the bottom of the margin.
*/
static readonly FIFTEEN_PERCENT: string = '15%';
}
\ No newline at end of file
... ...
// export default 'https://xfwbzshd.crgx.net'
// 后端域名
export default 'https://xfappht.crgx.net'
export default 'https://xfwbzshd.crgx.net'
// 正式后端域名
// export default 'https://xfappht.crgx.net'
// 前端地址
export const basePath = 'https://xfwbzs.crgx.net'
... ...
... ... @@ -4,7 +4,7 @@ import { promptAction } from '@kit.ArkUI'
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import { getCosKey, cosKeyTest, cosKeyData, uploadVideoOrImg } from '../api/cosKey'
import { AxiosResponse } from '@ohos/axios'
import { camera, cameraPicker } from '@kit.CameraKit'
// 选择一张图片或视频
export async function selectImgOrVideo(){
... ... @@ -18,6 +18,20 @@ export async function selectImgOrVideo(){
return photos.photoUris[0] // 返回文件路径
}
// 相机拍照
export async function selectImgByCamera(){
try {
let pickerProfile: cameraPicker.PickerProfile = {
cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK // 设置相机位置
}
let pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(getContext(),
[cameraPicker.PickerMediaType.PHOTO, cameraPicker.PickerMediaType.PHOTO], pickerProfile);
} catch (error) {
let err = error as BusinessError;
console.error(`Invoke uploadFile failed, code is ${err.code}, message is ${err.message}`)
}
}
/**
* 上传文件(通过uploadTask实现)
* @param context context
... ...
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import fs from '@ohos.file.fs';
import { request, BusinessError } from '@kit.BasicServicesKit';
import { cameraPicker as picker, camera } from '@kit.CameraKit';
import { common } from '@kit.AbilityKit';
import preferencesUtils from '../utils/preferences'
import { promptAction } from '@kit.ArkUI'
import { fileIo, fileUri } from '@kit.CoreFileKit'
import { VideoCompressor, CompressQuality, CompressorResponseCode } from '@ohos/videocompressor'
let mContext = getContext(this) as common.Context;
export interface uploadResult {
code?: number
msg?: string
... ... @@ -23,6 +30,67 @@ export async function selectImg(){
return photos.photoUris[0] // 返回图片路径
}
// 使用相机拍照
export async function cameraPickerImg() {
let pathDir = getContext().cacheDir;
let fileName = `${new Date().getTime()}`
let filePath = pathDir + `/${fileName}.tmp`
fileIo.createRandomAccessFileSync(filePath, fileIo.OpenMode.CREATE);
let uri = fileUri.getUriFromPath(filePath);
let pickerProfile: picker.PickerProfile = {
cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK,
saveUri: uri
};
try {
let result: picker.PickerResult = await picker.pick(getContext(), [picker.PickerMediaType.PHOTO], pickerProfile);
console.info(`picker resultCode: ${result.resultCode},resultUri: ${result.resultUri},mediaType: ${result.mediaType}`);
return result.resultUri
} catch (error) {
let err = error as BusinessError;
console.error(`the pick call failed. error code: ${err.code}`);
return ''
}
}
// 使用相机录像
export async function cameraPickerVideo() {
let pathDir = getContext().cacheDir;
let fileName = `${new Date().getTime()}`
let filePath = pathDir + `/${fileName}.tmp`
fileIo.createRandomAccessFileSync(filePath, fileIo.OpenMode.CREATE);
let uri = fileUri.getUriFromPath(filePath);
let pickerProfile: picker.PickerProfile = {
cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK,
saveUri: uri,
videoDuration: 120
};
try {
let result: picker.PickerResult = await picker.pick(getContext(), [picker.PickerMediaType.VIDEO], pickerProfile);
console.info(`picker resultCode: ${result.resultCode},resultUri: ${result.resultUri},mediaType: ${result.mediaType}`);
return result.resultUri
} catch (error) {
let err = error as BusinessError;
console.error(`the pick call failed. error code: ${err.code}`);
return ''
}
}
// 视频解码压缩
export async function videoCompressMethod(selectFilePath: string) {
let videoCompressor = new VideoCompressor();
const data = await videoCompressor.compressVideo(getContext(), selectFilePath, CompressQuality.COMPRESS_QUALITY_LOW) // 分别对应3个压缩质量 COMPRESS_QUALITY_HIGH,COMPRESS_QUALITY_MEDIUM, COMPRESS_QUALITY_LOW
if (data.code == CompressorResponseCode.SUCCESS) {
//outputPath: 压缩后的文件地址
console.log("videoCompressor HIGH message:" + data.message + "--outputPath:" + data.outputPath);
return data.outputPath
} else {
console.log("videoCompressor HIGH code:" + data.code + "--error message:" + data.message);
return ''
}
}
// 拷贝图片路径到缓存
export async function copyCachePath(systemPhotoImagePath: string) {
... ... @@ -42,6 +110,8 @@ export async function uploadFile() {
// 1. 完成图片上传并获得上传对象
try {
let systemPhotoImagePath = await selectImg() // 选择图片
// let systemPhotoImagePath = await cameraPickerImg() // 使用相机拍照
if(systemPhotoImagePath == '') return promptAction.showToast({message: '未选择图片'})
const fileData: string[] = await copyCachePath(systemPhotoImagePath)
let uploader = await request.uploadFile(getContext(),{ // 上传图片
url:'http://xfwbzshd.crgx.net/common/upload', // 请求地址
... ...
... ... @@ -8,7 +8,7 @@
},
{
"name": "ohos.permission.READ_MEDIA",
"reason": "$string:EntryAbility1_desc",
"reason": "$string:EntryAbilityReadFile_desc",
"usedScene": {
"abilities": [
"EntryAbility"
... ... @@ -18,13 +18,43 @@
},
{
"name": "ohos.permission.WRITE_MEDIA",
"reason": "$string:EntryAbility1_desc",
"reason": "$string:EntryAbilityReadFile_desc",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:EntryAbilityMicroPhone_desc",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "inuse"
}
},
{
"name": "ohos.permission.MEDIA_LOCATION",
"reason": "$string:EntryAbilityMedia_desc",
"usedScene": {
"abilities": [
"FormAbility"
],
"when":"always"
}
},
{
"name": "ohos.permission.CAMERA",
"reason": "$string:EntryAbilityCamera_desc",
"usedScene": {
"abilities": [
"EntryAbility"
],
"when": "always"
}
}
],
"description": "$string:module_desc",
... ...
... ... @@ -9,18 +9,30 @@
"value": "description"
},
{
"name": "EntryAbility1_desc",
"name": "EntryAbilityReadFile_desc",
"value": "读取文件"
},
{
"name": "EntryAbility2_desc",
"name": "EntryAbilityReadPhoto_desc",
"value": "读取相册"
},
{
"name": "EntryAbility3_desc",
"name": "EntryAbilitySharePlate_desc",
"value": "读取剪切板"
},
{
"name": "EntryAbilityMedia_desc",
"value": "访问你的地理位置"
},
{
"name": "EntryAbilityCamera_desc",
"value": "使用相机拍照录像"
},
{
"name": "EntryAbilityMicroPhone_desc",
"value": "使用你的麦克风录音"
},
{
"name": "EntryAbility_label",
"value": "消防维保助手"
},
... ...
<?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>
\ No newline at end of file
... ...
<?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>
\ No newline at end of file
... ...
... ... @@ -31,6 +31,6 @@
"pages/ViewFile",
"pages/StartAd",
"pages/AdMainPage",
"pages/SplashAdShowPage"
"pages/CreateCamera"
]
}
\ No newline at end of file
... ...
... ... @@ -9,8 +9,28 @@
"value": "description"
},
{
"name": "EntryAbilityReadFile_desc",
"value": "readFile"
},
{
"name": "EntryAbilityReadPhoto_desc",
"value": "readPhoto"
},
{
"name": "EntryAbilitySharePlate_desc",
"value": "readSharePlate"
},
{
"name": "EntryAbilityCamera_desc",
"value": "Use your camera for video recording"
},
{
"name": "EntryAbility_label",
"value": "消防维保助手"
"value": "Fire maintenance assistant"
},
{
"name": "video",
"value": "Fire maintenance assistant for advertising"
}
]
}
\ No newline at end of file
... ...
... ... @@ -9,20 +9,28 @@
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "消防维保助手"
},
{
"name": "EntryAbility1_desc",
"name": "EntryAbilityReadFile_desc",
"value": "读取文件"
},
{
"name": "EntryAbility2_desc",
"name": "EntryAbilityReadPhoto_desc",
"value": "读取相册"
},
{
"name": "EntryAbility3_desc",
"name": "EntryAbilitySharePlate_desc",
"value": "读取剪切板"
},
{
"name": "EntryAbilityCamera_desc",
"value": "使用相机拍照录像"
},
{
"name": "EntryAbility_label",
"value": "消防维保助手"
},
{
"name": "video",
"value": "消防维保助手广告"
}
]
}
\ No newline at end of file
... ...
... ... @@ -19,6 +19,7 @@
"@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0",
"@ohos/hypium@1.0.19": "@ohos/hypium@1.0.19",
"@ohos/lottie@^2.0.9": "@ohos/lottie@2.0.16",
"@ohos/videocompressor@^1.0.4": "@ohos/videocompressor@1.0.4",
"@wuyan/html_parse@^1.0.7": "@wuyan/html_parse@1.0.7",
"ksadsdk@entry/libs/KSAdSDK.har": "ksadsdk@entry/libs/KSAdSDK.har",
"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 @@
"resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/lottie/-/lottie-2.0.16.har",
"registryType": "ohpm"
},
"@ohos/videocompressor@1.0.4": {
"name": "@ohos/videocompressor",
"version": "1.0.4",
"integrity": "sha512-NGQOgKK81plBt7sfe314sp0U1B+r4eheYnsNI4CWG4PkJU6o4rU4lEGVDQ/wF/42RGYkwNw8A+tr26qXoX3kGQ==",
"resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/videocompressor/-/videocompressor-1.0.4.har",
"registryType": "ohpm"
},
"@wuyan/html_parse@1.0.7": {
"name": "@wuyan/html_parse",
"version": "1.0.7",
... ...
... ... @@ -9,7 +9,8 @@
"@csj/adapter_gdt": "^1.0.0-2",
"@csj/adapter_ks": "^2.0.3-beta-2",
"ksadsdk": "file:./entry/libs/KSAdSDK.har",
"@gdt/gdt-union-sdk": "file:./entry/libs/GDTUnionSDK-default-release.har"
"@gdt/gdt-union-sdk": "file:./entry/libs/GDTUnionSDK-default-release.har",
"@ohos/videocompressor": "^1.0.4"
},
"devDependencies": {
"@ohos/hypium": "1.0.19",
... ...