You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

290 lines
10 KiB

import * as w6s from 'szient-js-sdk'
import sha1 from 'crypto-js/sha1'
import { siqCode } from '@/api/enterprise'
import { baseUrl } from '@/config/env'
import { $globalStore } from '@/common/globalStore'
// ========== w6s 鉴权(参照 enterpriseHome.vue 的写法) ==========
const generateRandomNumber = () => {
const min = 100000
const max = 999999
const randomNum = (Math.floor(Math.random() * (max - min + 1)) + min)
return randomNum.toString().padStart(6, '0')
}
let w6sAuthPromise = null
// 确保 w6s 鉴权完成,缓存 Promise 避免重复鉴权
export const ensureW6sAuth = () => {
if (w6sAuthPromise) return w6sAuthPromise
w6sAuthPromise = new Promise((resolve, reject) => {
siqCode(null, success => {
let access_key = ''
let access_secret = ''
if (success.success) {
access_key = success.data.accessKey
access_secret = success.data.accessSecret
}
if (!access_key || !access_secret) {
w6sAuthPromise = null
reject(new Error('获取深i企认证信息错误: access_key 或 access_secret 为空'))
return
}
const nonce = generateRandomNumber()
const timestamp = `${Date.now()}`
const str = [access_secret, nonce, timestamp]
.sort()
.reduce((s, item) => s + item, '')
const signature = sha1(str).toString().toLowerCase()
w6s.config({
access_key: access_key,
nonce: nonce,
timestamp: timestamp,
signature: signature,
}).then((res) => {
console.log('w6s 鉴权成功', res)
}).catch((err) => {
w6sAuthPromise = null
reject(err)
})
w6s.ready(() => {
console.log('w6s ready')
resolve()
})
}, error => {
w6sAuthPromise = null
reject(error)
})
})
return w6sAuthPromise
}
// 格式化当前时间为 yyyy-MM-dd HH:mm:ss
const formatDateTime = () => {
const d = new Date()
const pad = (n) => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
}
// 拍照并加水印(时间戳 + 经纬度自动叠加到照片)
export const takePhotoWithWaterMark = async () => {
// 如果调用方未传 content,则默认显示当前时间作为水印文字
const watermarkContent = formatDateTime();
await ensureW6sAuth();
console.log('[w6sMedia] 鉴权完成, 准备调起拍照')
return new Promise((resolve, reject) => {
w6s.image.takePhotoAndAddWaterMark({
content: watermarkContent,
fontSize: 14,
color: '#FF5858',
2 months ago
markDisable: false,
timeEnable: true,
locationEnable: true,
success: (res) => {
console.log('[w6sMedia] takePhotoAndAddWaterMark success 原始返回:', res)
console.log('[w6sMedia] 返回字段 imageURL:', res?.result.imageURL, 'key:', res?.result.key, 'imageInfo:', res?.result.imageInfo)
resolve(res)
},
fail: (err) => {
console.error('[w6sMedia] takePhotoAndAddWaterMark fail:', err)
reject(err)
},
})
})
}
// 将 MediaFile 从公共目录复制到应用私有目录(解决 Android 11+ 分区存储导致的 EACCES 权限问题)
// 直接使用 MediaFile.file() 获取 FileEntry,避免 resolveLocalFileSystemURL 在公共目录路径上的限制
const copyMediaFileToAppDir = (mediaFile) => {
return new Promise((resolve, reject) => {
if (!window.cordova?.file?.dataDirectory) {
reject(new Error('cordova.file.dataDirectory 不可用'))
return
}
console.log('[w6sMedia] copyMediaFileToAppDir 开始, localURL:', mediaFile.localURL, 'fullPath:', mediaFile.fullPath)
// 通过 MediaFile.file() 获取 FileEntry(比 resolveLocalFileSystemURL 更可靠)
mediaFile.file(
(sourceFileEntry) => {
console.log('[w6sMedia] 获取源 FileEntry 成功:', sourceFileEntry.fullPath)
window.resolveLocalFileSystemURL(
window.cordova.file.dataDirectory,
(dataDirEntry) => {
console.log('[w6sMedia] 应用私有目录:', dataDirEntry.fullPath)
sourceFileEntry.copyTo(
dataDirEntry,
mediaFile.name,
(newFileEntry) => {
const fileUrl = newFileEntry.toURL()
console.log('[w6sMedia] 文件已复制到应用私有目录, fileUrl:', fileUrl)
resolve(fileUrl)
},
(copyErr) => {
// 目标文件已存在时,先删除再复制
console.warn('[w6sMedia] copyTo 可能目标已存在,尝试移除后重试:', copyErr)
window.resolveLocalFileSystemURL(
window.cordova.file.dataDirectory + mediaFile.name,
(existingEntry) => {
existingEntry.remove(
() => {
sourceFileEntry.copyTo(
dataDirEntry,
mediaFile.name,
(newFileEntry) => {
const fileUrl = newFileEntry.toURL()
console.log('[w6sMedia] 重试复制成功, fileUrl:', fileUrl)
resolve(fileUrl)
},
reject
)
},
() => {
// 无法删除旧文件,直接 resolve 原始 localURL
console.warn('[w6sMedia] 无法删除旧文件,返回原始 localURL')
resolve(mediaFile.localURL)
}
)
},
() => {
// 旧文件不存在,直接报错
reject(copyErr)
}
)
}
)
},
reject
)
},
(fileErr) => {
console.error('[w6sMedia] MediaFile.file() 失败:', fileErr)
reject(fileErr)
}
)
})
}
// 录制视频(使用 Cordova 原生 Media Capture API)
export const startVideoRecorder = async ({
duration = 0,
quality = 1, // 0 高清 / 1 一般 / 2 流畅
front = false,
syncSystemAlbum = false,
} = {}) => {
console.log('[w6sMedia] startVideoRecorder 开始, 入参:', { duration, quality, front, syncSystemAlbum })
await ensureW6sAuth()
console.log('[w6sMedia] 录制前鉴权完成, 准备调起录制')
return new Promise((resolve, reject) => {
if (!navigator?.device?.capture?.captureVideo) {
console.error('[w6sMedia] navigator.device.capture.captureVideo 不可用')
reject(new Error('当前环境不支持视频录制'))
return
}
navigator.device.capture.captureVideo(
async (mediaFiles) => {
console.log('[w6sMedia] captureVideo success, mediaFiles:', mediaFiles)
if (mediaFiles && mediaFiles.length > 0) {
const file = mediaFiles[0]
console.log('[w6sMedia] 视频文件: fullPath=', file.fullPath, 'localURL=', file.localURL, 'name=', file.name, 'size=', file.size)
try {
// 尝试将 MediaFile 复制到应用私有目录,获得可访问的 file:// URL
const appDirPath = await copyMediaFileToAppDir(file)
console.log('[w6sMedia] 视频已复制到应用私有目录:', appDirPath)
resolve({
video_path: appDirPath,
name: file.name,
size: file.size,
type: file.type || 'video/mp4',
})
} catch (copyErr) {
console.warn('[w6sMedia] 复制视频失败,尝试使用 localURL:', copyErr)
resolve({
video_path: file.localURL,
name: file.name,
size: file.size,
type: file.type || 'video/mp4',
})
}
} else {
reject(new Error('录制未生成视频文件'))
}
},
(error) => {
console.error('[w6sMedia] captureVideo fail:', error, 'code:', error?.code, 'message:', error?.message)
reject(error)
},
duration ? { limit: 1, duration } : { limit: 1 }
)
})
}
// 获取定位(经纬度)
export const getLocation = async () => {
await ensureW6sAuth()
return new Promise((resolve, reject) => {
w6s.location.getLocation({ success: resolve, fail: reject })
})
}
// 上传本地文件到后端 /app-enf/common/file/upload
// 使用 w6s.file.upload(Cordova FileTransfer),直接传本地路径,无需 base64 转换
export const uploadLocalFileToBackend = async ({
fileURL,
fileName = 'upload',
mimeType = 'image/jpeg',
}) => {
console.log('[w6sMedia] uploadLocalFileToBackend 开始, 入参:', { fileURL, fileName, mimeType })
await ensureW6sAuth()
console.log('[w6sMedia] 上传前鉴权完成')
return new Promise((resolve, reject) => {
const token = $globalStore.useCommon?.token || ''
const api = `${baseUrl}/app-enf/common/file/upload`
const server = /^https?:/.test(api) ? api : `${window.location.origin}${api}`
console.log('[w6sMedia] 上传目标 server:', server, 'token 存在:', !!token)
const opts = new window.FileUploadOptions()
opts.fileKey = 'file'
opts.fileName = fileName
opts.mimeType = mimeType
opts.headers = {
Authorization: token ? `Bearer ${token}` : '',
clientid: '9e6eb24cd4e169a98b0d2cd8034d877b',
}
console.log('[w6sMedia] FileUploadOptions 构造完成:', { fileKey: opts.fileKey, fileName: opts.fileName, mimeType: opts.mimeType })
w6s.file.upload(
{
fileURL,
server,
trustAllHosts: false,
success: (res) => {
console.log('[w6sMedia] file.upload success 原始返回:', res)
try {
const parsed = JSON.parse(res.response)
console.log('[w6sMedia] 解析后的上传响应:', parsed)
resolve(parsed)
} catch (e) {
console.warn('[w6sMedia] 响应 JSON 解析失败, 返回原始 response:', res.response)
resolve(res.response)
}
},
fail: (err) => {
console.error('[w6sMedia] file.upload fail:', err)
reject(err)
},
},
opts
).catch((err) => {
// w6s.file.upload 在 responseCode !== 200 时会 reject 但不调用 fail 回调
console.error('[w6sMedia] w6s.file.upload Promise reject:', err)
reject(err)
})
})
}