diff --git a/api/common/upload.js b/api/common/upload.js
index 9e4b7e3..9476d7b 100644
--- a/api/common/upload.js
+++ b/api/common/upload.js
@@ -1,7 +1,5 @@
import { getToken } from '@/util/auth'
-import request from "@/util/oaRequest"
-
-const BASE_URL = 'http://110.41.139.73:8080'
+import request, { BASE_URL } from "@/util/oaRequest"
export function uploadImage(filePath) {
console.log('[uploadImage] 开始上传:', filePath)
@@ -53,81 +51,74 @@ export function uploadImage(filePath) {
export function uploadFile(file, options = {}) {
const {
allowedTypes = ['doc', 'xls', 'ppt', 'txt', 'pdf', 'docx', 'xlsx', 'png', 'jpg', 'jpeg', 'zip', 'rar', '7z', 'dwg'],
- maxSize = 200, // 默认200MB
+ maxSize = 200,
extraData = 1
} = options
return new Promise((resolve, reject) => {
- // 文件类型验证
- const ext = file.name.split('.').pop().toLowerCase()
- if (allowedTypes && !allowedTypes.includes(ext)) {
- reject(new Error(`文件格式不正确,请上传${allowedTypes.join('/')}格式文件!`))
- return
- }
+ const fileName = file?.name || file?.fileName || file?.originalName || ''
+ const filePath = file?.path || file?.tempFilePath || file?.url || file?.filePath || ''
+ const fileSize = Number(file?.size || 0)
- // 文件大小验证
- if (maxSize && file.size / 1024 / 1024 > maxSize) {
- reject(new Error(`上传文件大小不能超过 ${maxSize} MB!`))
- return
- }
+ console.log('[uploadFile] 入参:', { fileName, filePath, fileSize, type: file?.type, raw: file })
- // 验证文件路径
- if (!file.path) {
+ if (!filePath) {
reject(new Error('文件路径为空'))
return
}
- console.log('[uploadFile] 开始上传文件:', {
- name: file.name,
- size: file.size,
- path: file.path,
- type: file.type
- })
+ const ext = (fileName.split('.').pop() || '').toLowerCase()
+ if (allowedTypes && ext && !allowedTypes.includes(ext)) {
+ reject(new Error(`文件格式不正确,请上传 ${allowedTypes.join('/')} 格式文件!`))
+ return
+ }
- // 处理文件路径(安卓平台)
- let filePath = file.path
+ if (maxSize && fileSize > 0 && fileSize / 1024 / 1024 > maxSize) {
+ reject(new Error(`上传文件大小不能超过 ${maxSize} MB!`))
+ return
+ }
+
+ let realPath = filePath
// #ifdef APP-PLUS
- if (typeof plus !== 'undefined' && plus.io) {
- if (!filePath.startsWith('/') && !filePath.startsWith('file://')) {
- filePath = plus.io.convertLocalFileSystemURL(filePath)
+ if (typeof plus !== 'undefined' && plus.io && realPath && !realPath.startsWith('file://') && !realPath.startsWith('/')) {
+ try {
+ realPath = plus.io.convertLocalFileSystemURL(realPath)
+ } catch (e) {
+ console.warn('[uploadFile] 路径转换失败,使用原始路径', e)
}
}
// #endif
+ console.log('[uploadFile] 开始上传文件:', { fileName, realPath, fileSize, type: file?.type })
+
uni.uploadFile({
url: BASE_URL + '/system/oss/upload',
- filePath,
+ filePath: realPath,
name: 'file',
- formData: {
- isPublic: extraData
- },
- header: {
- 'Authorization': 'Bearer ' + getToken()
- },
+ formData: { isPublic: extraData },
+ header: { Authorization: 'Bearer ' + getToken() },
success: (res) => {
console.log('[uploadFile] 上传响应:', res)
try {
const data = typeof res.data === 'string' ? JSON.parse(res.data) : res.data
if (data.code === 200) {
- console.log('[uploadFile] 上传成功:', data.data)
resolve({
ossId: data.data.ossId,
url: data.data.url,
fileName: data.data.fileName,
- originalName: file.name
+ originalName: fileName
})
} else {
- console.error('[uploadFile] 上传失败:', data)
- reject(data.msg || '上传失败')
+ reject(new Error(data.msg || '上传失败'))
}
} catch (e) {
console.error('[uploadFile] 解析返回数据失败:', e, res.data)
- reject('上传返回格式错误')
+ reject(new Error('上传返回格式错误'))
}
},
fail: (err) => {
console.error('[uploadFile] 上传接口调用失败:', err)
- reject(err)
+ reject(new Error(err?.errMsg || err?.message || '上传失败'))
}
})
})
@@ -139,7 +130,7 @@ export function uploadFile(file, options = {}) {
* @param {Object} options - 上传选项
* @returns {Promise} 返回上传结果数组
*/
-export function uploadFiles(files, options = {}) {
+export async function uploadFiles(files, options = {}) {
const {
allowedTypes = ['doc', 'xls', 'ppt', 'txt', 'pdf', 'docx', 'xlsx', 'png', 'jpg', 'jpeg', 'zip', 'rar', '7z', 'dwg'],
maxSize = 200,
@@ -205,7 +196,7 @@ export function listByIds(ossId) {
* @param {Array} ossIds - OSS ID数组
* @returns {Promise} 返回文件信息数组
*/
-export function getFilesByIds(ossIds) {
+export async function getFilesByIds(ossIds) {
if (!ossIds || ossIds.length === 0) {
return Promise.resolve([])
}
diff --git a/api/hrm/flow.js b/api/hrm/flow.js
index 7880b75..2416c9e 100644
--- a/api/hrm/flow.js
+++ b/api/hrm/flow.js
@@ -25,6 +25,14 @@ export function listTodoFlowTask(assigneeUserId) {
})
}
+export function listDoneFlowTask(userId, query) {
+ return request({
+ url: '/hrm/flow/task/historyList',
+ method: 'get',
+ params: { pageNum: 1, pageSize: 200, ...query }
+ })
+}
+
// 业务维度:按 bizType + bizId 查询当前待办任务(后端需提供)
export function getTodoTaskByBiz(bizType, bizId, assigneeUserId) {
return request({
diff --git a/package (2).json b/package (2).json
new file mode 100644
index 0000000..709d6b8
--- /dev/null
+++ b/package (2).json
@@ -0,0 +1,25 @@
+{
+ "id": "x-native-uploader",
+ "name": "x-native-uploader 原生文件上传组件",
+ "displayName": "x-native-uploader 原生文件上传组件",
+ "version": "1.0.2",
+ "description": "跨平台的文件上传组件,专为解决 UniApp 在 App 端文件选择与上传的痛点而设计。它集成了 Native.js 的能力,支持在 Android 和 iOS 上调用原生文件选择器",
+ "keywords": [
+ "文件上传"
+ ],
+ "dcloudext": {
+ "type": "component-vue",
+ "sale": {
+ "regular": {
+ "price": "0.00"
+ },
+ "sourcecode": {
+ "price": "0.00"
+ }
+ }
+ },
+ "uni_modules": {
+ "dependencies": [],
+ "encrypt": []
+ }
+}
\ No newline at end of file
diff --git a/pages.json b/pages.json
index da8d436..935ca99 100644
--- a/pages.json
+++ b/pages.json
@@ -1,6 +1,5 @@
{
"pages": [
- //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/login/index"
},
@@ -558,6 +557,41 @@
"navigationStyle": "default"
}
},
+ {
+ "path": "pages/workbench/hrm/leave/leave",
+ "style": {
+ "navigationBarTitleText": "请假申请",
+ "navigationStyle": "default"
+ }
+ },
+ {
+ "path": "pages/workbench/hrm/travel/travel",
+ "style": {
+ "navigationBarTitleText": "出差申请",
+ "navigationStyle": "default"
+ }
+ },
+ {
+ "path": "pages/workbench/hrm/seal/seal",
+ "style": {
+ "navigationBarTitleText": "用印申请",
+ "navigationStyle": "default"
+ }
+ },
+ {
+ "path": "pages/workbench/hrm/reimburse/reimburse",
+ "style": {
+ "navigationBarTitleText": "报销申请",
+ "navigationStyle": "default"
+ }
+ },
+ {
+ "path": "pages/workbench/hrm/apply/apply",
+ "style": {
+ "navigationBarTitleText": "拨款申请",
+ "navigationStyle": "default"
+ }
+ },
{
"path": "pages/workbench/hrm/approve/approve",
"style": {
@@ -579,18 +613,11 @@
"navigationStyle": "default"
}
},
- {
- "path": "pages/workbench/hrm/apply/apply",
- "style": {
- "navigationBarTitleText": "我的申请",
- "navigationStyle": "default"
- }
- },
{
"path": "pages/hrm/approve/approve",
"style": {
"navigationBarTitleText": "办公审批",
- "navigationStyle": "default"
+ "navigationStyle": "custom"
}
}
],
diff --git a/pages/hrm/approve/approve.vue b/pages/hrm/approve/approve.vue
index 89d0569..fba72ec 100644
--- a/pages/hrm/approve/approve.vue
+++ b/pages/hrm/approve/approve.vue
@@ -1,632 +1,640 @@
-
-
-
-
- {{ todoCount }}
- 待审批
-
+
+
+
+ 我的审批
+ 发起申请
-
-
-
- 申请类型:
-
- {{ bizTypeList[bizTypeIndex].label }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 暂无待审批任务
-
-
-
-
-
-
- {{ getBizTypeText(item.bizType) }}
-
-
-
-
-
-
- {{ formatApplicant(item) }}
+
+
+
+
+ 待处理
+
+
+ {{ summary.todo }}
+
- {{ formatRequestInfo(item) }}
-
- {{ formatDate(item.createTime) }}
+ 已处理
+ 抄送我
+
-
-
- {{ statusText(item.status) }}
+
+
+
+ 全部
+ {{ item.label }}
+
+
+
+
-
+
+
+
+
+
+
+
+
+ {{ emptyText }}
+
+
+
+ {{ getBizTypeText(item.bizType) }}
+
+
+
+ {{ formatApplicant(item) }}
+
+ {{ formatRequestInfo(item) }}
+ {{ formatDate(item.createTime || item.startTime) }}
+
+ {{ statusText(item.status) }}
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+ {{ item.desc }}
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/workbench/hrm/apply/apply.vue b/pages/workbench/hrm/apply/apply.vue
index 120c987..560bf52 100644
--- a/pages/workbench/hrm/apply/apply.vue
+++ b/pages/workbench/hrm/apply/apply.vue
@@ -1,627 +1,43 @@
-
-
-
-
- 申请类型:
-
- {{ bizTypeList[bizTypeIndex].label }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 暂无待审批任务
-
-
-
-
-
-
- {{ getBizTypeText(item.bizType) }}
-
-
-
-
-
-
- {{ item.bizTitle || '暂未标识' }}
-
-
-
- {{ formatDate(item.createTime) }}
-
-
-
-
- {{ statusText(item.status) }}
-
-
-
-
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/pages/workbench/hrm/leave/leave.vue b/pages/workbench/hrm/leave/leave.vue
index 1f29314..fa45e4d 100644
--- a/pages/workbench/hrm/leave/leave.vue
+++ b/pages/workbench/hrm/leave/leave.vue
@@ -1,946 +1,50 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ detail.leaveType || '请假申请' }}
-
- 申请编号:{{ detail.bizId || '-' }} ·
- 状态:{{ statusText }}
-
-
-
-
- 申请人
- {{ detail.createBy || '-' }}({{ detail.empNo }})
-
-
- 请假时长
- {{ detail.hours || '0' }} 小时
-
-
-
-
-
- 请假日期
-
-
-
- 开始时间
- {{ formatDate(detail.startTime) }}
-
-
- 结束时间
- {{ formatDate(detail.endTime) }}
-
-
- 请假类型
- {{ detail.leaveType || '-' }}
-
-
- 时长(小时)
- {{ detail.hours || '0' }} 小时
-
-
- 创建时间
- {{ formatDate(detail.createTime) }}
-
-
- 更新时间
- {{ formatDate(detail.updateTime) }}
-
-
-
-
-
- 请假理由说明
-
-
- 事由
- {{ detail.reason || '未填写' }}
-
-
- 工作交接
- {{ detail.handover }}
-
-
- 备注
- {{ detail.remark }}
-
-
-
-
- 申请附件
-
-
-
-
-
-
-
-
-
-
-
- {{ file.originalName || file.fileName || `文件${file.ossId}` }}
-
- {{ formatFileSize(file.fileSize) }}
- {{ formatDate(file.createTime) }}
-
-
-
-
-
-
-
-
-
- 暂无附件
-
-
-
-
- 审批意见
-
-
-
-
-
-
-
-
-
-
-
-
- 流转历史
-
-
-
-
-
-
- {{ formatDate(item.createTime) }}
-
- {{ getActionText(item.action) }}
- 处理人: {{ item.createBy || '系统' }}
-
-
-
-
-
- 暂无流转记录
-
-
-
-
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/pages/workbench/hrm/reimburse/reimburse.vue b/pages/workbench/hrm/reimburse/reimburse.vue
index 87b6899..e4c7fcb 100644
--- a/pages/workbench/hrm/reimburse/reimburse.vue
+++ b/pages/workbench/hrm/reimburse/reimburse.vue
@@ -1,22 +1,44 @@
-
-
-
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/pages/workbench/hrm/seal/seal.vue b/pages/workbench/hrm/seal/seal.vue
index 87b6899..9571623 100644
--- a/pages/workbench/hrm/seal/seal.vue
+++ b/pages/workbench/hrm/seal/seal.vue
@@ -1,22 +1,43 @@
-
-
-
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/pages/workbench/hrm/travel/travel.vue b/pages/workbench/hrm/travel/travel.vue
index 87b6899..0e84c10 100644
--- a/pages/workbench/hrm/travel/travel.vue
+++ b/pages/workbench/hrm/travel/travel.vue
@@ -1,22 +1,48 @@
-
-
-
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/uni_modules/uni-file-picker/changelog.md b/uni_modules/uni-file-picker/changelog.md
index fa33677..5320eb2 100644
--- a/uni_modules/uni-file-picker/changelog.md
+++ b/uni_modules/uni-file-picker/changelog.md
@@ -1,3 +1,13 @@
+## 1.1.3(2025-12-03)
+- 修复: 腾讯云目录错误导致的上传错误问题
+## 1.1.2(2025-09-17)
+- 修复 设置readonly属性后内容插槽失效的问题。
+## 1.1.1(2025-09-03)
+- 修复 动态dir目录,不生效的问题
+## 1.1.0(2025-09-02)
+- 新增 dir 属性,可以选择上传目录
+## 1.0.13(2025-08-18)
+- 修复 删除文件后,返回信息不包含file对象的问题
## 1.0.12(2025-04-14)
- 修复 支付宝小程序 上传样式问题
## 1.0.10(2024-07-09)
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue
index 872cf74..cf67ac7 100644
--- a/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue
@@ -4,17 +4,13 @@
{{ title }}
{{ filesList.length }}/{{ limitLength }}
-
+
-
+
@@ -181,18 +177,23 @@
sourceType: {
type: Array,
default () {
- return ['album', 'camera']
+ return ['album', 'camera']
}
},
provider: {
type: String,
default: '' // 默认上传到 unicloud 内置存储 extStorage 扩展存储
+ },
+ dir: {
+ type: String,
+ default: ''
}
},
data() {
return {
files: [],
- localValue: []
+ localValue: [],
+ dirPath: ''
}
},
watch: {
@@ -208,6 +209,12 @@
},
immediate: true
},
+ dir: {
+ handler(newVal) {
+ this.dirPath = newVal
+ },
+ immediate: true
+ },
},
computed: {
filesList() {
@@ -282,19 +289,19 @@
return this.uploadFiles(files)
},
async setValue(newVal, oldVal) {
- const newData = async (v) => {
+ const newData = async (v) => {
const reg = /cloud:\/\/([\w.]+\/?)\S*/
let url = ''
- if(v.fileID){
+ if (v.fileID) {
url = v.fileID
- }else{
+ } else {
url = v.url
}
if (reg.test(url)) {
v.fileID = url
v.url = await this.getTempFileURL(url)
}
- if(v.url) v.path = v.url
+ if (v.url) v.path = v.url
return v
}
if (this.returnType === 'object') {
@@ -305,13 +312,13 @@
}
} else {
if (!newVal) newVal = []
- for(let i =0 ;i < newVal.length ;i++){
+ for (let i = 0; i < newVal.length; i++) {
let v = newVal[i]
await newData(v)
}
}
this.localValue = newVal
- if (this.form && this.formItem &&!this.is_reset) {
+ if (this.form && this.formItem && !this.is_reset) {
this.is_reset = false
this.formItem.setValue(this.localValue)
}
@@ -368,7 +375,9 @@
* @param {Object} res
*/
async chooseFileCallback(res) {
+
const _extname = get_extname(this.fileExtname)
+
const is_one = (Number(this.limitLength) === 1 &&
this.disablePreview &&
!this.disabled) ||
@@ -394,11 +403,13 @@
let filedata = await get_file_data(files[i], this.fileMediatype)
filedata.progress = 0
filedata.status = 'ready'
- this.files.push(filedata)
- currentData.push({
+ // fix by mehaotian ,统一返回,删除也包含file对象
+ let fileTempData = {
...filedata,
file: files[i]
- })
+ }
+ this.files.push(fileTempData)
+ currentData.push(fileTempData)
}
this.$emit('select', {
tempFiles: currentData,
@@ -409,13 +420,24 @@
if (!this.autoUpload || this.noSpace) {
res.tempFiles = []
}
- res.tempFiles.forEach((fileItem, index) => {
+ res.tempFiles.map((fileItem, index) => {
this.provider && (fileItem.provider = this.provider);
const fileNameSplit = fileItem.name.split('.')
const ext = fileNameSplit.pop()
const fileName = fileNameSplit.join('.').replace(/[\s\/\?<>\\:\*\|":]/g, '_')
- fileItem.cloudPath = fileName + '_' + Date.now() + '_' + index + '.' + ext
+ // 选择文件目录上传
+ let dir = this.dirPath || ''; // 防止用户传入的 dir 不正常
+ // 检查最后一个字符是否为 '/'(同时处理空字符串情况)
+ if (dir && dir[dir.length - 1] !== '/') {
+ dir += '/';
+ }
+
+ fileItem.cloudPath = dir + fileName + '_' + Date.now() + '_' + index + '.' + ext
+ fileItem.cloudPathAsRealPath = true
+
+ return fileItem
})
+ return res
},
/**
@@ -462,7 +484,7 @@
const reg = /cloud:\/\/([\w.]+\/?)\S*/
if (reg.test(item.url)) {
this.files[index].url = await this.getTempFileURL(item.url)
- }else{
+ } else {
this.files[index].url = item.url
}
@@ -551,7 +573,7 @@
let data = []
if (this.returnType === 'object') {
data = this.backObject(this.files)[0]
- this.localValue = data?data:null
+ this.localValue = data ? data : null
} else {
data = this.backObject(this.files)
if (!this.localValue) {
@@ -581,12 +603,12 @@
name: v.name,
path: v.path,
size: v.size,
- fileID:v.fileID,
+ fileID: v.fileID,
url: v.url,
// 修改删除一个文件后不能再上传的bug, #694
- uuid: v.uuid,
- status: v.status,
- cloudPath: v.cloudPath
+ uuid: v.uuid,
+ status: v.status,
+ cloudPath: v.cloudPath
})
})
return newFilesData
diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue
index 625d92e..0d26379 100644
--- a/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue
+++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue
@@ -8,8 +8,7 @@
+ 'files-border':index !== 0 && styles.dividline}" :style="index !== 0 && styles.dividline &&borderLineStyle">