@@ -445,6 +475,10 @@ const taskSubTypes = ref([])
const fileList = ref([])
const uploadProgress = ref(0)
+// 预览图上传相关
+const previewFileList = ref([])
+const previewUploading = ref(false)
+
// 任务类型项接口
interface TaskTypeItem {
taskTypeId: number | undefined
@@ -467,6 +501,7 @@ const formData = reactive({
categoryId: undefined,
spuInfo: '',
attachmentUrl: '',
+ previewImage: '', // 预览图URL
remark: '', // 备注信息
releaseType: 'default',
// receiverId: undefined, // 已移除,改用子任务指定
@@ -570,6 +605,66 @@ const removeTaskType = (index: number) => {
}
}
+// 自动生成任务标题
+const generateTitle = () => {
+ const parts: string[] = []
+
+ // 1. SPU信息
+ if (formData.spuInfo && formData.spuInfo.trim()) {
+ parts.push(formData.spuInfo.trim())
+ }
+
+ // 2. 平台名称
+ if (formData.platformId) {
+ const platform = platforms.value.find((p: any) => p.id === formData.platformId)
+ if (platform) {
+ parts.push(platform.name)
+ }
+ }
+
+ // 3. 品牌名称
+ if (formData.brandId) {
+ const brand = brands.value.find((b: any) => b.id === formData.brandId)
+ if (brand) {
+ parts.push(brand.name)
+ }
+ }
+
+ // 4. 任务子类型
+ if (formData.taskSubType) {
+ parts.push(formData.taskSubType)
+ }
+
+ // 5. 需求类型(第一个任务类型名称)
+ if (formData.taskTypes.length > 0 && formData.taskTypes[0].taskTypeId) {
+ const taskType = taskTypes.value.find((t: any) => t.id === formData.taskTypes[0].taskTypeId)
+ if (taskType) {
+ parts.push(taskType.name)
+ }
+ }
+
+ // 生成标题
+ if (parts.length > 0) {
+ formData.title = parts.join('-')
+ }
+}
+
+// 监听相关字段变化,自动生成标题
+watch(
+ () => [
+ formData.spuInfo,
+ formData.platformId,
+ formData.brandId,
+ formData.taskSubType,
+ formData.taskTypes[0]?.taskTypeId
+ ],
+ () => {
+ // 只有当标题为空或是之前自动生成的标题时才自动更新
+ generateTitle()
+ },
+ { deep: true }
+)
+
// 计算预估积分(累加所有任务类型)
const estimatedScore = computed(() => {
let totalScore = 0
@@ -1035,6 +1130,74 @@ const handleRemove = (file: UploadFile) => {
return true
}
+// 预览图上传前验证
+const beforePreviewUpload = (file: File) => {
+ const isImage = file.type.startsWith('image/')
+ if (!isImage) {
+ message.error('只能上传图片文件')
+ return false
+ }
+ const isLt10M = file.size / 1024 / 1024 < 10
+ if (!isLt10M) {
+ message.error('图片大小不能超过 10MB')
+ return false
+ }
+ return true
+}
+
+// 预览图上传处理
+const handlePreviewUpload = async (options: any) => {
+ const { file, onSuccess, onError } = options
+
+ try {
+ previewUploading.value = true
+
+ const formDataObj = new FormData()
+ formDataObj.append('file', file)
+
+ const response = await fetch('/api/file/upload-preview', {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${localStorage.getItem('token')}`
+ },
+ body: formDataObj
+ })
+
+ const result = await response.json()
+
+ if (result.code === 200 && result.data) {
+ formData.previewImage = result.data
+ previewFileList.value = [{
+ uid: file.uid,
+ name: file.name,
+ status: 'done',
+ url: result.data
+ } as UploadFile]
+ if (onSuccess) {
+ onSuccess(result.data)
+ }
+ message.success('预览图上传成功')
+ } else {
+ throw new Error(result.msg || '上传失败')
+ }
+ } catch (error: any) {
+ console.error('预览图上传失败:', error)
+ if (onError) {
+ onError(error)
+ }
+ message.error('预览图上传失败: ' + error.message)
+ } finally {
+ previewUploading.value = false
+ }
+}
+
+// 删除预览图
+const handlePreviewRemove = () => {
+ formData.previewImage = ''
+ previewFileList.value = []
+ return true
+}
+
// 加载任务数据用于编辑
const loadTaskForEdit = async (taskId: number) => {
try {
@@ -1637,5 +1800,65 @@ onUnmounted(() => {
}
}
}
+
+// 任务标题自动生成提示
+.title-auto-tip {
+ margin-top: 8px;
+ font-size: 12px;
+ color: $text-muted;
+ display: flex;
+ align-items: center;
+}
+
+// 预览图上传区域
+.preview-upload-area {
+ .upload-button {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: $text-muted;
+
+ .upload-text {
+ margin-top: 8px;
+ font-size: 12px;
+ }
+ }
+
+ .preview-tip {
+ margin-top: 8px;
+ font-size: 12px;
+ color: $text-muted;
+ display: flex;
+ align-items: center;
+
+ .tip-icon {
+ margin-right: 6px;
+ }
+ }
+
+ :deep(.ant-upload-list-picture-card) {
+ .ant-upload-list-item {
+ border-color: rgba(255, 255, 255, 0.1);
+ background: rgba(255, 255, 255, 0.02);
+
+ &:hover {
+ border-color: $brand-primary;
+ }
+ }
+ }
+
+ :deep(.ant-upload-select-picture-card) {
+ width: 104px;
+ height: 104px;
+ background: rgba(255, 255, 255, 0.02);
+ border: 1px dashed rgba(255, 255, 255, 0.2);
+ border-radius: 8px;
+
+ &:hover {
+ border-color: $brand-primary;
+ }
+ }
+}
diff --git a/frontend/src/views/TaskHall.vue b/frontend/src/views/TaskHall.vue
index a160dae..21a1ba2 100644
--- a/frontend/src/views/TaskHall.vue
+++ b/frontend/src/views/TaskHall.vue
@@ -200,28 +200,37 @@
class="task-card chart-card"
@click="handleTaskClick(task)"
>
-
-
@@ -3918,11 +3929,11 @@ const handleConfigUpdate = async (event: CustomEvent) => {
}
// 组件挂载
-// 获取任务状态文本(增强版,支持区分驳回和草稿)
+// 获取任务状态文本(增强版,支持区分驳回、审核中和草稿)
const getTaskStatusText = (status: string, task?: any) => {
- // 如果有task对象,检查approvalStatus来区分驳回和草稿
+ // 如果有task对象,检查approvalStatus来区分不同状态
if (task) {
- // 检查是否被驳回(无论status是draft还是rejected)
+ // 1. 检查是否被驳回(无论status是draft还是rejected)
if (task.approvalStatus === 'rejected_by_demand' || task.approvalStatus === 'rejected_by_receiving') {
return '已驳回'
}
@@ -3930,6 +3941,32 @@ const getTaskStatusText = (status: string, task?: any) => {
if (status === 'rejected') {
return '已驳回'
}
+
+ // 2. 检查是否正在审核中
+ if (task.approvalStatus === 'pending_demand_approval') {
+ return '待部门审核'
+ }
+ if (task.approvalStatus === 'pending_receiving_approval') {
+ return '待接单审核'
+ }
+
+ // 3. 流水线任务且已审核通过,根据是否有接收人显示不同状态
+ if (task.isPipeline === 1 && task.approvalStatus === 'approved') {
+ if (task.receiverId) {
+ return '进行中'
+ } else {
+ return '待接单'
+ }
+ }
+
+ // 4. 普通任务已审核通过但status还是draft,修正显示
+ if (task.approvalStatus === 'approved' && status === 'draft') {
+ if (task.receiverId) {
+ return '进行中'
+ } else {
+ return '待接单'
+ }
+ }
}
const statusMap: Record = {
@@ -4371,6 +4408,39 @@ onUnmounted(() => {
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
+ // 带预览图的卡片布局
+ .card-with-preview {
+ display: flex;
+ gap: 16px;
+
+ .task-preview {
+ flex-shrink: 0;
+ width: 65px;
+ height: 65px;
+ border-radius: 8px;
+ overflow: hidden;
+ background: rgba(255, 255, 255, 0.05);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+ }
+
+ .card-content {
+ flex: 1;
+ min-width: 0;
+
+ &.has-preview {
+ .task-title {
+ font-size: 15px;
+ }
+ }
+ }
+ }
+
// 审核任务卡片特殊样式
.task-info-grid {
display: grid;