From 978b18d5d5fa0eb4a5ad5bb8b13c982af2a9e272 Mon Sep 17 00:00:00 2001 From: wlkjyy Date: Wed, 17 Dec 2025 15:42:14 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=E5=B7=A5=E5=8D=95=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E4=BC=98=E5=8C=96=20-=20=E6=94=B9=E4=B8=BA=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=BD=A2=E5=BC=8F=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E3=80=81=E7=8A=B6=E6=80=81=E4=BF=AE=E6=94=B9=E3=80=81?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E7=B2=98=E8=B4=B4=E6=8B=96=E6=8B=BD=E7=AD=89?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/ticket.js | 9 +- src/views/product/ProductList.vue | 20 +++- src/views/ticket/TicketDetail.vue | 176 ++++++++++++++++++++++++++++-- src/views/ticket/TicketList.vue | 53 ++++++++- 4 files changed, 236 insertions(+), 22 deletions(-) diff --git a/src/api/ticket.js b/src/api/ticket.js index 47f9dbd..7ea0668 100644 --- a/src/api/ticket.js +++ b/src/api/ticket.js @@ -5,8 +5,13 @@ import request from "@/utils/request.js"; * @returns {Promise} */ -export function getTickerList(count, page, status) { - return request.get('/api/v1/admin/work_order/list', { count, page, status }) +export function getTickerList(count, page, status, orderBy, order) { + const params = { count, page } + if (status !== undefined && status !== '') params.status = status + if (orderBy) params.orderBy = orderBy + if (order) params.order = order + console.log('工单列表请求参数:', params) // 调试日志 + return request.get('/api/v1/admin/work_order/list', params) } // 待处理 diff --git a/src/views/product/ProductList.vue b/src/views/product/ProductList.vue index f658d7d..e0da797 100644 --- a/src/views/product/ProductList.vue +++ b/src/views/product/ProductList.vue @@ -678,7 +678,10 @@ const paramValueForm = reactive({ attr_id: undefined, attr_name: '', attr_value: '', - attr_price: 0 + attr_price: 0, + index: 0, + attr_range: 0, + range_type: 'equal' }) const paramValueRules = { @@ -825,7 +828,10 @@ const handleAddParamValue = () => { attr_id: undefined, attr_name: '', attr_value: '', - attr_price: 0 + attr_price: 0, + index: 0, + attr_range: 0, + range_type: 'equal' }) paramValueFormRef.value?.resetFields() } @@ -838,7 +844,10 @@ const handleEditParamValue = (row) => { attr_id: row.id, attr_name: row.name, attr_value: row.value, - attr_price: row.price / 100 + attr_price: row.price / 100, + index: row.index || 0, + attr_range: row.attr_range || 0, + range_type: row.range_type || 'equal' }) } @@ -872,7 +881,10 @@ const submitParamValueForm = () => { arg_id: Number(currentParam.value.id), attr_name: paramValueForm.attr_name, attr_value: paramValueForm.attr_value, - attr_price: paramValueForm.attr_price + attr_price: paramValueForm.attr_price, + index: Number(paramValueForm.index), + attr_range: Number(paramValueForm.attr_range), + range_type: paramValueForm.range_type } if (paramValueFormType.value === 'edit') { submitData.attr_id = paramValueForm.attr_id diff --git a/src/views/ticket/TicketDetail.vue b/src/views/ticket/TicketDetail.vue index 4d123e1..c4b5d4d 100644 --- a/src/views/ticket/TicketDetail.vue +++ b/src/views/ticket/TicketDetail.vue @@ -56,9 +56,17 @@
工单号: {{ ticketInfo.id }} - - {{ getStatusText(ticketInfo.status) }} - + + + + + + -
+
@@ -174,7 +190,7 @@ import { ref, onMounted, nextTick, onBeforeUnmount, watch } from 'vue' import { useRoute, useRouter } from 'vue-router' import { ElMessage, ElMessageBox } from 'element-plus' -import { getTicketDetail, replyTicket, closeTicket } from '@/api/ticket' +import { getTicketDetail, replyTicket, closeTicket, updateTicketInfo } from '@/api/ticket' import { getUserInfo } from '@/api/admin/user' import { uploadFile } from '@/api/admin/file' import { useUserStore } from '@/store/userStore' @@ -200,6 +216,8 @@ const messageInput = ref('') const selectedImages = ref([]) const selectedFiles = ref([]) // 存储原始文件对象 const messagesContainer = ref(null) +const textareaRef = ref(null) +const isDragOver = ref(false) // 图片查看 const imageViewerVisible = ref(false) @@ -283,7 +301,7 @@ const fetchTicketDetail = async (showLoading = true) => { if (res.code === 200) { const detail = res.data ticketInfo.value = { - id: detail.work_id, + id: detail.id, title: detail.name, username: detail.user?.userName || `用户${detail.user?.userId || 'Unknown'}`, userId: detail.user?.userId, @@ -432,6 +450,38 @@ const sendMessage = async () => { } } +// 修改工单状态 +const handleStatusChange = async (newStatus) => { + const statusMap = { + 'pending': 0, + 'processing': 1, + 'replied': 2, + 'completed': 3 + } + + const oldStatus = ticketInfo.value.status + + try { + const formData = new FormData() + formData.append('work_id', route.query.id) + formData.append('Status', statusMap[newStatus]) + + const res = await updateTicketInfo(formData) + + if (res.code === 200) { + ElMessage.success('工单状态已更新') + ticketInfo.value.status = newStatus + } else { + ElMessage.error(res.message || '更新失败') + ticketInfo.value.status = oldStatus // 恢复原状态 + } + } catch (error) { + console.error('更新工单状态出错:', error) + ElMessage.error('网络错误,请稍后重试') + ticketInfo.value.status = oldStatus // 恢复原状态 + } +} + // 结束工单 const handleComplete = () => { ElMessageBox.confirm('确定要结束此工单吗?结束后将无法继续回复。', '确认操作', { @@ -456,14 +506,81 @@ const handleComplete = () => { // 图片处理 const handleFileChange = (file) => { if (!file) return + addImageFile(file.raw) +} + +// 添加图片文件(统一处理函数) +const addImageFile = (file) => { + // 验证文件类型 + if (!file.type.startsWith('image/')) { + ElMessage.warning('只支持图片格式') + return + } + + // 验证文件大小(限制10MB) + if (file.size > 10 * 1024 * 1024) { + ElMessage.warning('图片大小不能超过10MB') + return + } // 保存原始文件对象用于上传 - selectedFiles.value.push(file.raw) + selectedFiles.value.push(file) // 读取文件用于预览 const reader = new FileReader() reader.onload = (e) => selectedImages.value.push(e.target.result) - reader.readAsDataURL(file.raw) + reader.readAsDataURL(file) +} + +// 处理粘贴事件 +const handlePaste = (e) => { + const items = e.clipboardData?.items + if (!items) return + + for (let i = 0; i < items.length; i++) { + const item = items[i] + if (item.type.indexOf('image') !== -1) { + e.preventDefault() + const file = item.getAsFile() + if (file) { + addImageFile(file) + ElMessage.success('图片已添加') + } + } + } +} + +// 处理拖拽进入 +const handleDragOver = (e) => { + isDragOver.value = true +} + +// 处理拖拽离开 +const handleDragLeave = (e) => { + isDragOver.value = false +} + +// 处理文件拖放 +const handleDrop = (e) => { + isDragOver.value = false + + const files = e.dataTransfer?.files + if (!files || files.length === 0) return + + let addedCount = 0 + for (let i = 0; i < files.length; i++) { + const file = files[i] + if (file.type.startsWith('image/')) { + addImageFile(file) + addedCount++ + } + } + + if (addedCount > 0) { + ElMessage.success(`已添加 ${addedCount} 张图片`) + } else { + ElMessage.warning('未找到图片文件') + } } const removeImage = (index) => { @@ -606,10 +723,24 @@ watch( onMounted(() => { fetchTicketDetail() startAutoRefresh() + + // 绑定粘贴事件到原生 textarea + nextTick(() => { + const textarea = textareaRef.value?.$el?.querySelector('textarea') + if (textarea) { + textarea.addEventListener('paste', handlePaste) + } + }) }) onBeforeUnmount(() => { stopAutoRefresh() + + // 移除粘贴事件监听 + const textarea = textareaRef.value?.$el?.querySelector('textarea') + if (textarea) { + textarea.removeEventListener('paste', handlePaste) + } }) @@ -645,7 +776,10 @@ onBeforeUnmount(() => { .ticket-id { font-weight: 500; - color: #606266; + color: #303133; + font-size: 14px; + white-space: nowrap; + flex-shrink: 0; } .user-info { @@ -849,6 +983,28 @@ onBeforeUnmount(() => { display: flex; flex-direction: column; gap: 12px; + position: relative; + transition: all 0.3s; +} + +.input-area.drag-over { + background: #f0f9ff; + border: 2px dashed #409eff; + border-radius: 4px; + padding: 8px; +} + +.input-area.drag-over::before { + content: '释放以添加图片'; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + color: #409eff; + font-size: 14px; + font-weight: 500; + pointer-events: none; + z-index: 1; } .input-actions { diff --git a/src/views/ticket/TicketList.vue b/src/views/ticket/TicketList.vue index c09bc62..64fd0d9 100644 --- a/src/views/ticket/TicketList.vue +++ b/src/views/ticket/TicketList.vue @@ -3,9 +3,6 @@
-
- 全部 {{ stats.total }} -
待处理 {{ stats.pending }}
@@ -18,8 +15,22 @@
已完成 {{ stats.completed }}
+
+ 全部 {{ stats.total }} +
+ + + + + + + + + + +