oa_app仓库初始化
This commit is contained in:
+230
@@ -0,0 +1,230 @@
|
||||
import { OA_BASE, IM_HTTP } from './config.js'
|
||||
import { toast } from './format.js'
|
||||
|
||||
export function fileId(file) {
|
||||
if (file == null) return ''
|
||||
if (typeof file === 'string' || typeof file === 'number') {
|
||||
const s = String(file)
|
||||
return !s || s === '0' || s === 'null' ? '' : s
|
||||
}
|
||||
const id = file.id ?? file.fileId
|
||||
if (id == null || id === '' || id === 0 || id === '0' || id === 'null') return ''
|
||||
return String(id)
|
||||
}
|
||||
|
||||
export function fileName(file, fallback = '附件') {
|
||||
if (!file || typeof file !== 'object') return fallback
|
||||
return String(file.name || file.fileName || file.originalName || fallback)
|
||||
}
|
||||
|
||||
export function isImageFile(file) {
|
||||
const name = fileName(file, '')
|
||||
const type = String((file && file.contentType) || '').toLowerCase()
|
||||
return type.startsWith('image/') || /\.(png|jpe?g|gif|webp|bmp|heic)$/i.test(name)
|
||||
}
|
||||
|
||||
function unwrapUpload(body) {
|
||||
if (!body || typeof body !== 'object') return body
|
||||
if (body.code != null && body.code !== 0 && body.code !== 200) {
|
||||
throw new Error(body.message || '上传失败')
|
||||
}
|
||||
return Object.prototype.hasOwnProperty.call(body, 'data') ? body.data : body
|
||||
}
|
||||
|
||||
export function uploadLocal(filePath, token, { kind = 'attach', name } = {}) {
|
||||
const urls = [`${OA_BASE}/api/files`, `${IM_HTTP}/api/im/oa/files`]
|
||||
const send = (url) => new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url,
|
||||
filePath,
|
||||
name: 'file',
|
||||
formData: { kind, ...(kind === 'im' || kind === 'IM' ? { bizType: 'im' } : {}) },
|
||||
header: token ? { Authorization: 'Bearer ' + token } : {},
|
||||
timeout: 120000,
|
||||
success(res) {
|
||||
let body = res.data
|
||||
try { body = typeof body === 'string' ? JSON.parse(body) : body } catch (_) {}
|
||||
if (res.statusCode >= 400) {
|
||||
reject(new Error((body && body.message) || `上传失败 ${res.statusCode}`))
|
||||
return
|
||||
}
|
||||
try {
|
||||
const data = unwrapUpload(body)
|
||||
const id = fileId(data)
|
||||
if (!id) throw new Error((body && body.message) || '上传未返回文件')
|
||||
resolve({
|
||||
id,
|
||||
name: (data && data.name) || name || '附件',
|
||||
size: (data && data.size) || 0,
|
||||
contentType: (data && data.contentType) || ''
|
||||
})
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
},
|
||||
fail(e) {
|
||||
reject(new Error((e && e.errMsg) || '上传失败'))
|
||||
}
|
||||
})
|
||||
})
|
||||
return send(urls[0]).catch(() => send(urls[1]))
|
||||
}
|
||||
|
||||
export function fileTicket(id, token) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const urls = [`${OA_BASE}/api/files/${id}/ticket`, `${IM_HTTP}/api/im/oa/files/${id}/ticket`]
|
||||
const post = (url, next) => {
|
||||
uni.request({
|
||||
url,
|
||||
method: 'POST',
|
||||
header: {
|
||||
Accept: 'application/json',
|
||||
...(token ? { Authorization: 'Bearer ' + token } : {})
|
||||
},
|
||||
success(res) {
|
||||
const body = res.data
|
||||
if (res.statusCode >= 400) {
|
||||
if (next) return next()
|
||||
reject(new Error((body && body.message) || '无法预览'))
|
||||
return
|
||||
}
|
||||
const data = body && body.data !== undefined ? body.data : body
|
||||
if (data && data.url) {
|
||||
resolve(data)
|
||||
return
|
||||
}
|
||||
if (next) return next()
|
||||
reject(new Error('无法预览'))
|
||||
},
|
||||
fail() {
|
||||
if (next) next()
|
||||
else reject(new Error('无法预览'))
|
||||
}
|
||||
})
|
||||
}
|
||||
post(urls[0], () => post(urls[1], null))
|
||||
})
|
||||
}
|
||||
|
||||
export async function openFile(file, token) {
|
||||
const id = fileId(file)
|
||||
if (!id) {
|
||||
toast('文件未迁移或无法预览')
|
||||
return
|
||||
}
|
||||
try {
|
||||
uni.showLoading({ title: '打开附件…', mask: true })
|
||||
const ticket = await fileTicket(id, token)
|
||||
const url = ticket.url
|
||||
uni.hideLoading()
|
||||
if (isImageFile(file)) {
|
||||
uni.previewImage({ urls: [url], current: url })
|
||||
return
|
||||
}
|
||||
uni.downloadFile({
|
||||
url,
|
||||
header: token ? { Authorization: 'Bearer ' + token } : {},
|
||||
success(res) {
|
||||
if (res.statusCode === 200 && res.tempFilePath) {
|
||||
uni.openDocument({
|
||||
filePath: res.tempFilePath,
|
||||
showMenu: true,
|
||||
fail() {
|
||||
plus.runtime.openURL(url)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
toast('下载失败')
|
||||
}
|
||||
},
|
||||
fail() {
|
||||
try { plus.runtime.openURL(url) } catch (_) { toast('无法打开附件') }
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
toast((e && e.message) || '无法预览附件')
|
||||
}
|
||||
}
|
||||
|
||||
function uploadPaths(paths, token, kind) {
|
||||
return Promise.all(paths.map((p) => uploadLocal(p, token, { kind })))
|
||||
}
|
||||
|
||||
export function pickAndUpload(token, kind = 'attach') {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fromImages = () => {
|
||||
uni.chooseImage({
|
||||
count: 6,
|
||||
sizeType: ['compressed', 'original'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success(res) {
|
||||
const paths = res.tempFilePaths || []
|
||||
if (!paths.length) return resolve([])
|
||||
uni.showLoading({ title: '上传中…', mask: true })
|
||||
uploadPaths(paths, token, kind)
|
||||
.then((rows) => { uni.hideLoading(); resolve(rows) })
|
||||
.catch((e) => { uni.hideLoading(); reject(e) })
|
||||
},
|
||||
fail() { resolve([]) }
|
||||
})
|
||||
}
|
||||
const fromFiles = () => {
|
||||
const chooser = typeof uni.chooseFile === 'function' ? uni.chooseFile : null
|
||||
if (!chooser) return fromImages()
|
||||
chooser({
|
||||
count: 6,
|
||||
type: 'all',
|
||||
extension: ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.pdf', '.doc', '.docx', '.xls', '.xlsx'],
|
||||
success(res) {
|
||||
const files = res.tempFiles || []
|
||||
const paths = files.map((f) => f.path || f.tempFilePath).filter(Boolean)
|
||||
if (!paths.length) return resolve([])
|
||||
uni.showLoading({ title: '上传中…', mask: true })
|
||||
uploadPaths(paths, token, kind)
|
||||
.then((rows) => { uni.hideLoading(); resolve(rows) })
|
||||
.catch((e) => { uni.hideLoading(); reject(e) })
|
||||
},
|
||||
fail() { resolve([]) }
|
||||
})
|
||||
}
|
||||
uni.showActionSheet({
|
||||
itemList: ['拍照或相册', '选择文件'],
|
||||
success(res) {
|
||||
if (res.tapIndex === 0) fromImages()
|
||||
else fromFiles()
|
||||
},
|
||||
fail() { resolve([]) }
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function collectFiles(row) {
|
||||
const out = []
|
||||
const seen = new Set()
|
||||
const push = (f) => {
|
||||
if (!f) return
|
||||
const id = fileId(f)
|
||||
const key = id || fileName(f)
|
||||
if (!key || seen.has(key)) return
|
||||
seen.add(key)
|
||||
out.push(typeof f === 'object' ? f : { id })
|
||||
}
|
||||
const walk = (v) => {
|
||||
if (!v) return
|
||||
if (Array.isArray(v)) v.forEach(walk)
|
||||
else if (typeof v === 'object') {
|
||||
if (fileId(v) || v.name) push(v)
|
||||
}
|
||||
}
|
||||
if (!row || typeof row !== 'object') return out
|
||||
walk(row.files)
|
||||
walk(row.attachments)
|
||||
walk(row.invoiceFiles)
|
||||
walk(row.receiptFiles)
|
||||
const form = row.form && typeof row.form === 'object' ? row.form : row
|
||||
walk(form.files)
|
||||
walk(form.attachments)
|
||||
;(form.invoices || row.invoices || []).forEach((inv) => walk(inv && inv.files))
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user