From 9c7b0a23730097068f238d911e8d330ce619dd9d Mon Sep 17 00:00:00 2001 From: WindowBird <13870814+windows-bird@user.noreply.gitee.com> Date: Mon, 17 Nov 2025 09:22:06 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E8=A7=A3=E5=86=B3=EF=BC=9A=E6=9C=AA?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=20custom.catch:=20true=EF=BC=8C=E4=BC=9A?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E4=B8=80=E4=B8=AA=E6=B0=B8=E8=BF=9C=20pendin?= =?UTF-8?q?g=20=E7=9A=84=20Promise?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/task.js | 3 ++- pages/task/add/index.vue | 10 ++++------ utils/request/index.js | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/api/task.js b/api/task.js index 120eeb9..ea7c936 100644 --- a/api/task.js +++ b/api/task.js @@ -106,7 +106,8 @@ export const applyTaskDelay = (payload) => { export const createTask = (payload) => { return uni.$uv.http.post('/bst/task', payload, { custom: { - auth: true + auth: true, + catch: true // 允许在 catch 中处理错误 } }); }; diff --git a/pages/task/add/index.vue b/pages/task/add/index.vue index b4c3b03..1f6148b 100644 --- a/pages/task/add/index.vue +++ b/pages/task/add/index.vue @@ -862,7 +862,8 @@ const handleSubmit = async () => { }); try { - await createTask(payload); + const res = await createTask(payload); + console.log('@@@@@@@@@@',res); uni.hideLoading(); uni.showToast({ title: '创建成功', @@ -874,14 +875,11 @@ const handleSubmit = async () => { }, 1200); } catch (error) { uni.hideLoading(); - submitting.value = false; console.error('创建任务失败:', error); - uni.showToast({ - title: error.message || '创建失败,请重试', - icon: 'none' - }); + // 错误提示已在响应拦截器中统一处理,这里不需要重复显示 } finally { submitting.value = false; + console.log('submitting', submitting.value); } }; diff --git a/utils/request/index.js b/utils/request/index.js index 1a9501b..814ab9f 100644 --- a/utils/request/index.js +++ b/utils/request/index.js @@ -10,7 +10,7 @@ export const Request = () => { // 初始化请求配置 uni.$uv.http.setConfig((config) => { /* config 为默认全局配置*/ - config.baseURL = 'http://192.168.1.5:4001'; /* 根域名 */ + config.baseURL = 'http://192.168.1.9:4001'; /* 根域名 */ // config.baseURL = 'https://pm.ccttiot.com/prod-api'; /* 根域名 */ return config }) From ca4f03b1d536f7e4c57484de3123cd815a30a4dd Mon Sep 17 00:00:00 2001 From: WindowBird <13870814+windows-bird@user.noreply.gitee.com> Date: Mon, 17 Nov 2025 10:30:03 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BB=BB=E5=8A=A1?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=95=B0=E6=8D=AE=E5=8F=91=E9=80=81=E4=BA=8C?= =?UTF-8?q?=E6=AC=A1=E8=AF=B7=E6=B1=82=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/task/detail/index.vue | 46 ++++++++++++++++++------------------- pages/task/list/index.vue | 21 +++++++++-------- pages/task/submit/index.vue | 1 - 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/pages/task/detail/index.vue b/pages/task/detail/index.vue index c4dd45b..2810f66 100644 --- a/pages/task/detail/index.vue +++ b/pages/task/detail/index.vue @@ -269,23 +269,19 @@ const determineTaskStatus = (status, expireTime) => { const now = new Date(); // 设置时间到当天0点,便于日期比较 - now.setHours(0, 0, 0, 0); - expireDate.setHours(23, 59, 59, 999); - + // now.setHours(0, 0, 0, 0); + // expireDate.setHours(23, 59, 59, 999); // 如果已过期,标记为逾期 if (expireDate.getTime() < now.getTime()) { return 'overdue'; } - // 计算距离过期的天数 const diffTime = expireDate.getTime() - now.getTime(); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); - // 如果3天内到期,标记为即将逾期 if (diffDays <= 3 && diffDays > 0) { return 'imminent'; } - // 否则返回待完成状态 return 'pending'; }; @@ -722,24 +718,26 @@ onLoad((options) => { task.value.id = taskId; // 优先从 API 加载数据 loadTaskData(taskId); - } else { - // 如果没有 taskId,尝试从 Pinia store 获取任务详情数据(兼容旧逻辑) - const taskStore = useTaskStore(); - const storedTask = taskStore.getTaskDetail; - if (storedTask) { - task.value = { - ...task.value, - ...storedTask - }; - } else { - uni.showToast({ - title: '缺少任务ID', - icon: 'none' - }); - setTimeout(() => { - uni.navigateBack(); - }, 1500); - } + } + else { + // // 如果没有 taskId,尝试从 Pinia store 获取任务详情数据(兼容旧逻辑) + // const taskStore = useTaskStore(); + // const storedTask = taskStore.getTaskDetail; + // if (storedTask) { + // task.value = { + // ...task.value, + // ...storedTask + // }; + // } + // else { + // uni.showToast({ + // title: '缺少任务ID', + // icon: 'none' + // }); + // setTimeout(() => { + // uni.navigateBack(); + // }, 1500); + // } } }); diff --git a/pages/task/list/index.vue b/pages/task/list/index.vue index 99cd41c..35caaf1 100644 --- a/pages/task/list/index.vue +++ b/pages/task/list/index.vue @@ -87,7 +87,7 @@ diff --git a/pages/task/submit/index.vue b/pages/task/submit/index.vue index 471bc9a..857cc49 100644 --- a/pages/task/submit/index.vue +++ b/pages/task/submit/index.vue @@ -796,7 +796,6 @@ const handleSubmit = async () => { } .form-label { - flex: 1; font-size: 15px; color: #333; } From a983e545fce1283f2cadad544a072c8c89ee35b3 Mon Sep 17 00:00:00 2001 From: WindowBird <13870814+windows-bird@user.noreply.gitee.com> Date: Mon, 17 Nov 2025 10:36:28 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=96=B0=E5=BB=BA?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E9=A1=B5=E9=9D=A2=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/task/add/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/task/add/index.vue b/pages/task/add/index.vue index 1f6148b..384f678 100644 --- a/pages/task/add/index.vue +++ b/pages/task/add/index.vue @@ -1266,7 +1266,7 @@ onLoad(async (options) => { } .form-label { - flex: 1; + font-size: 15px; color: #333; } From d530bd5fd80b187bda310bb80ec736ff4cdf7a2c Mon Sep 17 00:00:00 2001 From: WindowBird <13870814+windows-bird@user.noreply.gitee.com> Date: Mon, 17 Nov 2025 11:04:57 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E8=AF=A6=E7=BB=86?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=96=87=E4=BB=B6=E6=98=BE=E7=A4=BA=E4=B8=8E?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/task/detail/index.vue | 131 +++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-) diff --git a/pages/task/detail/index.vue b/pages/task/detail/index.vue index 2810f66..d292223 100644 --- a/pages/task/detail/index.vue +++ b/pages/task/detail/index.vue @@ -88,6 +88,21 @@ /> + + + + {{ getFileIcon(file.name) }} + + {{ file.name }} + {{ formatFileSize(file.size) }} + + + 申请延期 @@ -325,6 +340,32 @@ const isImageUrl = (url) => { return /\.(jpg|jpeg|png|gif|bmp|webp)(\?|$)/i.test(url); }; +// 解析任务附件(区分图片和文件) +const parseTaskAttachments = (attachStr) => { + if (!attachStr) return { pictures: [], files: [] }; + if (typeof attachStr !== 'string') return { pictures: [], files: [] }; + + const urls = parseAttachUrls(attachStr); + const pictures = []; + const files = []; + + urls.forEach(url => { + if (isImageUrl(url)) { + pictures.push(url); + } else { + // 从URL中提取文件名 + const fileName = url.split('/').pop().split('?')[0] || '文件'; + files.push({ + name: fileName, + path: url, + size: 0 // 如果API没有返回文件大小,默认为0 + }); + } + }); + + return { pictures, files }; +}; + // 转换提交记录数据 const transformSubmitRecords = (submitList) => { if (!Array.isArray(submitList) || submitList.length === 0) { @@ -488,6 +529,73 @@ const previewTaskImages = (imageUrls, index) => { } }; +// 预览/下载任务文件 +const previewTaskFile = (file) => { + if (!file.path) { + uni.showToast({ + title: '文件路径不存在', + icon: 'none' + }); + return; + } + + // 如果是图片,使用预览图片功能 + const imageExts = ['jpg', 'jpeg', 'png', 'gif', 'webp']; + const ext = file.name ? file.name.split('.').pop().toLowerCase() : ''; + + if (imageExts.includes(ext)) { + uni.previewImage({ + urls: [file.path], + current: file.path + }); + } else { + // 其他文件类型,尝试打开或下载 + // #ifdef H5 + window.open(file.path, '_blank'); + // #endif + + // #ifdef APP-PLUS + plus.runtime.openURL(file.path); + // #endif + + // #ifndef H5 || APP-PLUS + uni.showToast({ + title: '正在下载文件...', + icon: 'loading', + duration: 2000 + }); + // 下载并打开文档 + uni.downloadFile({ + url: file.path, + success: (res) => { + if (res.statusCode === 200) { + uni.openDocument({ + filePath: res.tempFilePath, + success: () => { + console.log('打开文档成功'); + }, + fail: (err) => { + console.error('打开文档失败:', err); + uni.showToast({ + title: '无法打开此文件', + icon: 'none' + }); + } + }); + } + }, + fail: (err) => { + console.error('下载文件失败:', err); + uni.showToast({ + title: '下载文件失败', + icon: 'none' + }); + } + }); + // #endif + } +}; + // 预览提交记录图片 const previewRecordImages = (imageUrls, index) => { if (imageUrls && imageUrls.length > 0) { @@ -679,8 +787,16 @@ const loadTaskData = async (taskId) => { // 转换提交记录 const submitRecords = transformSubmitRecords(res.submitList || []); - // 解析任务图片(逗号分隔的URL字符串) - const taskPictures = res.picture ? parseAttachUrls(res.picture) : []; + // 解析任务附件(图片和文件) + // 优先使用 file 字段,如果没有则使用 picture 字段(可能包含图片和文件) + let taskAttachments = { pictures: [], files: [] }; + if (res.file) { + // 如果 API 返回了 file 字段,解析它 + taskAttachments = parseTaskAttachments(res.file); + } else if (res.picture) { + // 如果只有 picture 字段,也解析它(可能包含图片和文件) + taskAttachments = parseTaskAttachments(res.picture); + } // 更新任务数据 task.value = { @@ -694,7 +810,8 @@ const loadTaskData = async (taskId) => { responsible: getOwnerNames(res.memberList || []), publishTime: res.createTime ? formatTimeToChinese(res.createTime) : '', content: res.description || '', - pictures: taskPictures, // 任务图片数组 + pictures: taskAttachments.pictures, // 任务图片数组 + files: taskAttachments.files, // 任务文件数组 submitRecords: submitRecords, // 保存原始数据,供其他功能使用 rawData: res @@ -1185,6 +1302,14 @@ onShow(() => { object-fit: cover; } +/* 任务文件展示 */ +.task-files-wrapper { + display: flex; + flex-direction: column; + gap: 8px; + margin-bottom: 16px; +} + /* 提交记录图片展示(一行三个) */ .record-images-wrapper { display: flex; From 97c07ff5d88d0f23d7abd3d759167c3636163a69 Mon Sep 17 00:00:00 2001 From: WindowBird <13870814+windows-bird@user.noreply.gitee.com> Date: Mon, 17 Nov 2025 11:58:49 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/index.js | 5 +- api/project.js | 102 +++++ components/index/Workbench.vue | 6 + pages.json | 6 + pages/project/list/index.vue | 661 +++++++++++++++++++++++++++++++++ 5 files changed, 779 insertions(+), 1 deletion(-) create mode 100644 api/project.js create mode 100644 pages/project/list/index.vue diff --git a/api/index.js b/api/index.js index aa61f9b..74d9675 100644 --- a/api/index.js +++ b/api/index.js @@ -26,4 +26,7 @@ export * from './customer'; export * from './common'; // 导入审批相关 API -export * from './verify'; \ No newline at end of file +export * from './verify'; + +// 导入项目相关 API +export * from './project'; \ No newline at end of file diff --git a/api/project.js b/api/project.js new file mode 100644 index 0000000..a887eec --- /dev/null +++ b/api/project.js @@ -0,0 +1,102 @@ +/** + * 项目相关 API + */ + +/** + * 获取项目列表 + * @param {Object} params 请求参数 + * @param {number} params.pageNum 页码 + * @param {number} params.pageSize 每页数量 + * @param {string} params.orderByColumn 排序字段 + * @param {string} params.isAsc 排序方式(ascending/descending) + * @param {number[]} params.statusList 项目状态列表 + * @param {string} params.createId 创建人ID + * @param {string} params.ownerId 负责人ID + * @param {string[]} params.keys 搜索关键词数组 + * @returns {Promise} 返回项目列表 + */ +export const getProjectList = (params = {}) => { + const queryParams = []; + + // 分页参数 + if (params.pageNum !== undefined) { + queryParams.push(`pageNum=${params.pageNum}`); + } + if (params.pageSize !== undefined) { + queryParams.push(`pageSize=${params.pageSize}`); + } + + // 排序参数 + if (params.orderByColumn !== undefined && params.orderByColumn !== '') { + queryParams.push(`orderByColumn=${encodeURIComponent(params.orderByColumn)}`); + } + if (params.isAsc !== undefined && params.isAsc !== '') { + queryParams.push(`isAsc=${encodeURIComponent(params.isAsc)}`); + } + + // 状态列表 + if (params.statusList !== undefined && Array.isArray(params.statusList) && params.statusList.length > 0) { + params.statusList.forEach((status, index) => { + queryParams.push(`statusList=${status}`); + }); + } + + // 创建人ID + if (params.createId !== undefined && params.createId !== '') { + queryParams.push(`createId=${params.createId}`); + } + + // 负责人ID + if (params.ownerId !== undefined && params.ownerId !== '') { + queryParams.push(`ownerId=${params.ownerId}`); + } + + // 搜索关键词 + if (params.keys !== undefined && Array.isArray(params.keys) && params.keys.length > 0) { + params.keys.forEach((key, index) => { + queryParams.push(`keys[${index}]=${encodeURIComponent(key)}`); + }); + } + + // 项目名称搜索 + if (params.projectName !== undefined && params.projectName !== '') { + queryParams.push(`projectName=${encodeURIComponent(params.projectName)}`); + } + + // 项目编号搜索 + if (params.projectId !== undefined && params.projectId !== '') { + queryParams.push(`projectId=${encodeURIComponent(params.projectId)}`); + } + + // 客户名称搜索 + if (params.customerName !== undefined && params.customerName !== '') { + queryParams.push(`customerName=${encodeURIComponent(params.customerName)}`); + } + + // 成员ID搜索 + if (params.memberId !== undefined && params.memberId !== '') { + queryParams.push(`memberId=${params.memberId}`); + } + + const queryString = queryParams.length > 0 ? `?${queryParams.join('&')}` : ''; + + return uni.$uv.http.get(`bst/project/list${queryString}`, { + custom: { + auth: true // 启用 token 认证 + } + }); +}; + +/** + * 获取项目详情 + * @param {string} id 项目ID + * @returns {Promise} 返回项目详情 + */ +export const getProjectDetail = (id) => { + return uni.$uv.http.get(`bst/project/${id}`, { + custom: { + auth: true + } + }); +}; + diff --git a/components/index/Workbench.vue b/components/index/Workbench.vue index e707423..61a8851 100644 --- a/components/index/Workbench.vue +++ b/components/index/Workbench.vue @@ -62,6 +62,12 @@ const handleClick = (item) => { uni.switchTab({ url: '/pages/index/index' }); return; } + if (item.key === 'project') { + uni.navigateTo({ + url: '/pages/project/list/index' + }); + return; + } // 其他入口占位 uni.showToast({ title: '开发中', icon: 'none' }); }; diff --git a/pages.json b/pages.json index c4d18d4..a06ec67 100644 --- a/pages.json +++ b/pages.json @@ -137,6 +137,12 @@ "navigationBarTitleText": "修改跟进记录", "navigationStyle": "custom" } + }, + { + "path": "pages/project/list/index", + "style": { + "navigationBarTitleText": "项目管理" + } } ], diff --git a/pages/project/list/index.vue b/pages/project/list/index.vue new file mode 100644 index 0000000..55a6a96 --- /dev/null +++ b/pages/project/list/index.vue @@ -0,0 +1,661 @@ + + + + + +