From c77086ad2d7949ab36dd0c4e0b59907e672dd64f Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期五, 18 九月 2026 15:04:42 +0800
Subject: [PATCH] Merge remote-tracking branch 'refs/remotes/origin/dev_pro2.0' into dev_宁夏_九泓化工

---
 src/views/aftersales/ticket/detail.vue |  179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 174 insertions(+), 5 deletions(-)

diff --git a/src/views/aftersales/ticket/detail.vue b/src/views/aftersales/ticket/detail.vue
index b9a6d7e..092ebc2 100644
--- a/src/views/aftersales/ticket/detail.vue
+++ b/src/views/aftersales/ticket/detail.vue
@@ -7,7 +7,17 @@
 import { Page } from '@vben/common-ui';
 import { AftersaleIssueTypeEnum, AftersaleTicketStatusEnum } from '@vben/constants';
 
-import { Button, Card, Descriptions, Input, message, Popconfirm, Select, Tag } from 'ant-design-vue';
+import {
+  Button,
+  Card,
+  Descriptions,
+  Input,
+  message,
+  Popconfirm,
+  Select,
+  Switch,
+  Tag,
+} from 'ant-design-vue';
 
 import {
   assignTicket,
@@ -17,6 +27,11 @@
   getTicket,
   resolveTicket,
 } from '#/api/aftersales/ticket';
+import type { AftersalesVisitApi } from '#/api/aftersales/visit';
+import {
+  createVisit,
+  getVisitListByTicketId,
+} from '#/api/aftersales/visit';
 
 defineOptions({ name: 'AftersalesTicketDetail' });
 
@@ -32,6 +47,32 @@
 const isPendingReturn = computed(() => ticket.value?.status === AftersaleTicketStatusEnum.PENDING_RETURN);
 const isPendingRefund = computed(() => ticket.value?.status === AftersaleTicketStatusEnum.PENDING_REFUND);
 const isResolved = computed(() => ticket.value?.status === AftersaleTicketStatusEnum.RESOLVED);
+/** 鍥炶鏄惁宸查�氳繃锛堟弧鎰忎笖鏈鍙戯級 */
+const isVisitPassed = computed(() => ticket.value?.visitStatus === 1);
+
+// 鍥炶璁板綍
+const visits = ref<AftersalesVisitApi.Visit[]>([]);
+const showVisitForm = ref(false);
+const visitForm = ref<AftersalesVisitApi.CreateVisit>({
+  ticketId: 0,
+  visitType: 0,
+  content: '',
+  satisfied: true,
+  recurred: false,
+});
+
+const visitTypeOptions = [
+  { label: '鐢佃瘽鍥炶', value: 0 },
+  { label: '涓婇棬鍥炶', value: 1 },
+  { label: '杩滅▼鍥炶', value: 2 },
+  { label: '鍏朵粬', value: 3 },
+];
+const visitTypeMap: Record<number, string> = {
+  0: '鐢佃瘽',
+  1: '涓婇棬',
+  2: '杩滅▼',
+  3: '鍏朵粬',
+};
 
 // 鍒嗛厤澶勭悊浜�
 const showAssignInput = ref(false);
@@ -86,6 +127,30 @@
   } finally {
     loading.value = false;
   }
+}
+
+async function loadVisits() {
+  visits.value = await getVisitListByTicketId(ticketId.value);
+}
+
+function toggleVisitForm() {
+  showVisitForm.value = !showVisitForm.value;
+  if (showVisitForm.value) {
+    visitForm.value = {
+      ticketId: ticketId.value,
+      visitType: 0,
+      content: '',
+      satisfied: true,
+      recurred: false,
+    };
+  }
+}
+
+async function handleCreateVisit() {
+  await createVisit({ ...visitForm.value, ticketId: ticketId.value });
+  message.success('鍥炶鐧昏鎴愬姛');
+  showVisitForm.value = false;
+  await Promise.all([loadVisits(), loadTicket()]);
 }
 
 function toggleAssignInput() {
@@ -161,6 +226,7 @@
 
 onMounted(() => {
   loadTicket();
+  loadVisits();
 });
 </script>
 
@@ -195,6 +261,14 @@
         </Descriptions.Item>
         <Descriptions.Item label="璐熻矗浜�">{{ ticket.ownerUserName || '-' }}</Descriptions.Item>
         <Descriptions.Item label="澶勭悊浜�">{{ ticket.handlerUserName || '-' }}</Descriptions.Item>
+        <Descriptions.Item label="鍥炶鐘舵��">
+          <Tag v-if="ticket.visitStatus === 1" color="green">宸插洖璁块�氳繃</Tag>
+          <Tag v-else color="orange">寰呭洖璁�</Tag>
+        </Descriptions.Item>
+        <Descriptions.Item label="闂娌夋穩" :span="2">
+          <template v-if="ticket.problemNo">{{ ticket.problemNo }}</template>
+          <template v-else>-</template>
+        </Descriptions.Item>
         <Descriptions.Item label="闂鎻忚堪" :span="3">
           {{ ticket.issueDescription || '-' }}
         </Descriptions.Item>
@@ -253,6 +327,101 @@
         >
           {{ file.name || '闄勪欢-' + file.id }}
         </a>
+      </div>
+    </Card>
+
+    <!-- 鍥炶璁板綍 -->
+    <Card v-if="ticket" title="鍥炶璁板綍" class="mb-4">
+      <template #extra>
+        <Button
+          v-if="isResolved && !showVisitForm"
+          type="primary"
+          size="small"
+          @click="toggleVisitForm"
+        >
+          鐧昏鍥炶
+        </Button>
+      </template>
+
+      <div v-if="isResolved" class="mb-3 text-sm text-gray-500">
+        鐧昏銆屾弧鎰� 涓� 鏈鍙戙�嶇殑鍥炶鍚庯紝宸ュ崟鎵嶅彲褰掓。锛涚櫥璁般�屼笉婊℃剰鎴栧鍙戙�嶄細鑷姩閫�鍥炲鐞嗕腑銆�
+      </div>
+
+      <!-- 鐧昏鍥炶琛ㄥ崟 -->
+      <div
+        v-if="showVisitForm"
+        class="mb-4 flex flex-wrap items-center gap-3 rounded bg-gray-50 p-3"
+      >
+        <div class="flex items-center gap-1">
+          <span class="text-sm text-gray-500">鍥炶鏂瑰紡锛�</span>
+          <Select
+            v-model:value="visitForm.visitType"
+            :options="visitTypeOptions"
+            style="width: 120px"
+          />
+        </div>
+        <div class="flex items-center gap-1">
+          <span class="text-sm text-gray-500">鍥炶鍐呭锛�</span>
+          <Input
+            v-model:value="visitForm.content"
+            placeholder="瀹㈡埛鍙嶉鍐呭"
+            style="width: 260px"
+          />
+        </div>
+        <div class="flex items-center gap-1">
+          <span class="text-sm text-gray-500">鏄惁婊℃剰锛�</span>
+          <Switch
+            v-model:checked="visitForm.satisfied"
+            checked-children="婊℃剰"
+            un-checked-children="涓嶆弧鎰�"
+          />
+        </div>
+        <div class="flex items-center gap-1">
+          <span class="text-sm text-gray-500">鏄惁澶嶅彂锛�</span>
+          <Switch
+            v-model:checked="visitForm.recurred"
+            checked-children="澶嶅彂"
+            un-checked-children="鏈鍙�"
+          />
+        </div>
+        <Button type="primary" size="small" @click="handleCreateVisit">鎻愪氦</Button>
+        <Button size="small" @click="toggleVisitForm">鍙栨秷</Button>
+      </div>
+
+      <!-- 鍥炶璁板綍鍒楄〃 -->
+      <div v-if="visits.length === 0" class="text-sm text-gray-400">鏆傛棤鍥炶璁板綍</div>
+      <div v-else class="overflow-x-auto">
+        <table class="w-full border text-sm">
+          <thead class="bg-gray-50">
+            <tr>
+              <th class="border p-2 text-left">鍥炶鏃堕棿</th>
+              <th class="border p-2 text-left">鏂瑰紡</th>
+              <th class="border p-2 text-left">鍥炶浜�</th>
+              <th class="border p-2 text-center">婊℃剰</th>
+              <th class="border p-2 text-center">澶嶅彂</th>
+              <th class="border p-2 text-left">鍐呭</th>
+              <th class="border p-2 text-left">澶囨敞</th>
+            </tr>
+          </thead>
+          <tbody>
+            <tr v-for="visit in visits" :key="visit.id">
+              <td class="border p-2">{{ visit.visitTime }}</td>
+              <td class="border p-2">{{ visitTypeMap[visit.visitType!] ?? '-' }}</td>
+              <td class="border p-2">{{ visit.visitorUserName || '-' }}</td>
+              <td class="border p-2 text-center">
+                <Tag :color="visit.satisfied ? 'green' : 'red'">
+                  {{ visit.satisfied ? '婊℃剰' : '涓嶆弧鎰�' }}
+                </Tag>
+              </td>
+              <td class="border p-2 text-center">
+                <Tag v-if="visit.recurred" color="orange">澶嶅彂</Tag>
+                <Tag v-else color="default">鏈鍙�</Tag>
+              </td>
+              <td class="border p-2">{{ visit.content || '-' }}</td>
+              <td class="border p-2">{{ visit.remark || '-' }}</td>
+            </tr>
+          </tbody>
+        </table>
       </div>
     </Card>
 
@@ -323,13 +492,13 @@
           <Button type="primary">瀹岀粨</Button>
         </Popconfirm>
 
-        <!-- 鍏抽棴 -->
+        <!-- 褰掓。锛堜粎鍥炶閫氳繃鍚庡彲褰掓。锛涙湭鍥炶璇峰湪鈥滃洖璁胯褰曗�濋噷鐧昏锛� -->
         <Popconfirm
-          v-if="isResolved"
-          title="纭鍏抽棴璇ュ伐鍗曪紵鍏抽棴鍚庝笉鍙仮澶嶃��"
+          v-if="isResolved && isVisitPassed"
+          title="纭褰掓。璇ュ伐鍗曪紵褰掓。鍚庤嚜鍔ㄦ矇娣�涓�鏉¢棶棰橈紝宸ュ崟鍙涓嶅彲鎭㈠銆�"
           @confirm="handleClose"
         >
-          <Button type="primary">鍏抽棴</Button>
+          <Button type="primary">褰掓。</Button>
         </Popconfirm>
 
         <!-- 鍙栨秷 -->

--
Gitblit v1.9.3