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 @@
+
+
+
+
+
+
+ 客户
+
+
+
+ 项目编号
+
+
+
+
+
+ 项目名称
+
+
+
+ 成员
+
+
+ {{ selectedMemberName || '请选择用户' }}
+ ▼
+
+
+
+
+
+
+
+ 开发超期
+
+
+ 全部
+
+
+ 是
+
+
+ 否
+
+
+
+
+
+
+
+ {{ tab.label }}
+
+
+
+
+
+
+ 🔍
+ 搜索
+
+
+ 重置
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ project.projectName }}
+ {{ project.description }}
+
+
+ 创建人: {{ project.createName }}
+ 负责人: {{ getOwnerNames(project.memberList) }}
+
+ 提交: {{ project.submitCount || 0 }}次
+ 接收: {{ project.receivedCount || 0 }}次
+
+
+
+
+
+ ⚠️ 已逾期
+
+
+
+
+
+
+ 加载中...
+
+
+
+
+ 暂无项目数据
+
+
+
+
+ 上拉加载更多
+
+
+ 没有更多数据了
+
+
+
+
+
+
+
+
+
+