From 39f6fca28e3f78abe48f08e474ec011abb990b36 Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期三, 09 九月 2026 10:39:21 +0800
Subject: [PATCH] update

---
 frontend/src/views/GuideTeamDetailView.vue |  151 +++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 131 insertions(+), 20 deletions(-)

diff --git a/frontend/src/views/GuideTeamDetailView.vue b/frontend/src/views/GuideTeamDetailView.vue
index 1e4ecff..75a6ca2 100644
--- a/frontend/src/views/GuideTeamDetailView.vue
+++ b/frontend/src/views/GuideTeamDetailView.vue
@@ -3,25 +3,38 @@
 import { useRoute, useRouter } from 'vue-router'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { ArrowLeft, Edit, Plus } from '@element-plus/icons-vue'
-import { createGuideTeam, getGuideTeamDetail, updateGuideTeam } from '@/api/guideTeams'
+import {
+  createGuideTeam,
+  getGuideTeamCollectionGuideOptions,
+  getGuideTeamDetail,
+  updateGuideTeam,
+} from '@/api/guideTeams'
+import { getScenicSpotDetail, getScenicSpots } from '@/api/scenicSpots'
 
 const route = useRoute()
 const router = useRouter()
 const loading = ref(false)
 const saving = ref(false)
+const collectionGuideLoading = ref(false)
+const collectionGuideOptions = ref([])
 const formRef = ref()
 const scenicFormRef = ref()
 const scenicDialogVisible = ref(false)
 const scenicEditingIndex = ref(-1)
+const scenicOptionsLoading = ref(false)
+const scenicDetailLoading = ref(false)
+const scenicOptions = ref([])
+const meetingPointOptions = ref([])
 const isCreate = computed(() => route.name === 'guide-team-create')
 const isEdit = computed(() => route.name === 'guide-team-edit')
 const readonly = computed(() => route.name === 'guide-team-detail')
 const pageTitle = computed(() => isCreate.value ? '新增讲解队' : isEdit.value ? '编辑讲解队' : '讲解队详情')
 const form = reactive({
   id: null, teamName: '', contactPhone: '', createdAt: '', companyName: '',
-  unifiedSocialCreditCode: '', commissionRatio: null, wechatOpenId: '', merchantId: '', scenicConfigs: [],
+  unifiedSocialCreditCode: '', commissionRatio: null, wechatOpenId: '', merchantId: '',
+  balance: 0, collectionGuideId: null, scenicConfigs: [],
 })
-const scenicForm = reactive({ scenicName: '', cityName: '', meetingPoints: '' })
+const scenicForm = reactive({ scenicSpotId: null, scenicName: '', cityName: '', meetingPointNames: [] })
 const rules = {
   teamName: [
     { required: true, message: '请输入讲解队名称', trigger: 'blur' },
@@ -36,12 +49,12 @@
   ],
 }
 const scenicRules = {
-  scenicName: [{ required: true, message: '请输入景区名称', trigger: 'blur' }],
-  cityName: [{ required: true, message: '请输入城市', trigger: 'blur' }],
-  meetingPoints: [{ required: true, message: '请输入汇合点', trigger: 'blur' }],
+  scenicSpotId: [{ required: true, message: '请选择景区', trigger: 'change' }],
+  meetingPointNames: [{ required: true, type: 'array', min: 1, message: '请选择汇合点', trigger: 'change' }],
 }
 
 const formatDateTime = (value) => value ? value.replace('T', ' ').slice(0, 19) : '-'
+const formatMoney = (value) => `¥${Number(value || 0).toFixed(2)}`
 const assignDetail = (detail) => Object.assign(form, {
   id: detail.id,
   teamName: detail.teamName || '',
@@ -52,30 +65,74 @@
   commissionRatio: detail.commissionRatio ?? 0,
   wechatOpenId: detail.wechatOpenId || '',
   merchantId: detail.merchantId || '',
+  balance: detail.balance ?? 0,
+  collectionGuideId: detail.collectionGuideId ?? null,
   scenicConfigs: (detail.scenicConfigs || []).map((item) => ({ ...item })),
 })
+const loadCollectionGuideOptions = async () => {
+  if (isCreate.value) return
+  collectionGuideLoading.value = true
+  try { collectionGuideOptions.value = await getGuideTeamCollectionGuideOptions(route.params.id) }
+  finally { collectionGuideLoading.value = false }
+}
 const loadDetail = async () => {
   if (isCreate.value) { form.commissionRatio = 0; return }
   loading.value = true
-  try { assignDetail(await getGuideTeamDetail(route.params.id)) }
+  try {
+    assignDetail(await getGuideTeamDetail(route.params.id))
+    await loadCollectionGuideOptions()
+  }
   finally { loading.value = false }
 }
+const loadScenicOptions = async () => {
+  scenicOptionsLoading.value = true
+  try {
+    const result = await getScenicSpots({ page: 1, size: 100, status: 1 })
+    scenicOptions.value = result.records || []
+  } finally { scenicOptionsLoading.value = false }
+}
+const selectScenic = async (scenicSpotId, preserveMeetingPoints = false) => {
+  const selected = scenicOptions.value.find((item) => item.id === scenicSpotId)
+  scenicForm.scenicName = selected?.scenicName || ''
+  scenicForm.cityName = selected?.cityName || ''
+  if (!preserveMeetingPoints) scenicForm.meetingPointNames = []
+  meetingPointOptions.value = []
+  if (!scenicSpotId) return
+  scenicDetailLoading.value = true
+  try {
+    const detail = await getScenicSpotDetail(scenicSpotId)
+    meetingPointOptions.value = (detail.meetingPoints || []).filter((point) => point.status === 1)
+  } finally { scenicDetailLoading.value = false }
+}
+const findScenicOption = (row) => scenicOptions.value.find((item) => (
+  item.scenicName === row.scenicName && item.cityName === row.cityName
+))
+const splitMeetingPoints = (value) => String(value || '').split(/[,,]/).map((item) => item.trim()).filter(Boolean)
 const openScenicCreate = () => {
   scenicEditingIndex.value = -1
-  Object.assign(scenicForm, { scenicName: '', cityName: '', meetingPoints: '' })
+  Object.assign(scenicForm, { scenicSpotId: null, scenicName: '', cityName: '', meetingPointNames: [] })
+  meetingPointOptions.value = []
   scenicDialogVisible.value = true
 }
-const openScenicEdit = (row, index) => {
+const openScenicEdit = async (row, index) => {
   scenicEditingIndex.value = index
-  Object.assign(scenicForm, { scenicName: row.scenicName, cityName: row.cityName, meetingPoints: row.meetingPoints })
+  const selected = findScenicOption(row)
+  Object.assign(scenicForm, {
+    scenicSpotId: selected?.id || null,
+    scenicName: row.scenicName,
+    cityName: row.cityName,
+    meetingPointNames: splitMeetingPoints(row.meetingPoints),
+  })
+  meetingPointOptions.value = []
   scenicDialogVisible.value = true
+  if (selected) await selectScenic(selected.id, true)
 }
 const saveScenic = async () => {
   await scenicFormRef.value.validate()
   const value = {
-    scenicName: scenicForm.scenicName.trim(),
-    cityName: scenicForm.cityName.trim(),
-    meetingPoints: scenicForm.meetingPoints.trim(),
+    scenicName: scenicForm.scenicName,
+    cityName: scenicForm.cityName,
+    meetingPoints: scenicForm.meetingPointNames.join(','),
   }
   const duplicated = form.scenicConfigs.some((item, index) => (
     index !== scenicEditingIndex.value && item.scenicName.trim() === value.scenicName
@@ -98,6 +155,10 @@
 }
 const save = async () => {
   await formRef.value.validate()
+  if (!form.scenicConfigs.length) {
+    ElMessage.warning('请至少配置一个景区')
+    return
+  }
   if (!form.wechatOpenId.trim() && !form.merchantId.trim()) {
     ElMessage.warning('openID和商户ID至少配置一个')
     return
@@ -112,6 +173,7 @@
       commissionRatio: form.commissionRatio,
       wechatOpenId: form.wechatOpenId.trim() || null,
       merchantId: form.merchantId.trim() || null,
+      collectionGuideId: form.collectionGuideId,
       scenicConfigs: form.scenicConfigs,
     }
     const result = isCreate.value ? await createGuideTeam(payload) : await updateGuideTeam(route.params.id, payload)
@@ -121,7 +183,7 @@
   } finally { saving.value = false }
 }
 
-onMounted(loadDetail)
+onMounted(() => Promise.all([loadDetail(), loadScenicOptions()]))
 </script>
 
 <template>
@@ -148,6 +210,9 @@
             </el-form-item>
             <el-form-item label="注册时间">
               <el-input :model-value="formatDateTime(form.createdAt)" disabled />
+            </el-form-item>
+            <el-form-item label="讲解队余额">
+              <el-input :model-value="formatMoney(form.balance)" disabled />
             </el-form-item>
             <el-form-item label="企业名称">
               <el-input v-model="form.companyName" :disabled="readonly" maxlength="200" />
@@ -187,6 +252,23 @@
             <span>openID和商户ID至少配置一个</span>
           </div>
           <div class="collection-grid">
+            <el-form-item label="收款导游">
+              <el-select
+                v-model="form.collectionGuideId"
+                :disabled="readonly || isCreate"
+                :loading="collectionGuideLoading"
+                clearable
+                placeholder="请选择收款导游"
+              >
+                <el-option
+                  v-for="guide in collectionGuideOptions"
+                  :key="guide.id"
+                  :label="`${guide.realName || '-'} ${guide.mobile || ''}${guide.unavailableReason ? `(${guide.unavailableReason})` : ''}`"
+                  :value="guide.id"
+                  :disabled="!guide.configurable && guide.id !== form.collectionGuideId"
+                />
+              </el-select>
+            </el-form-item>
             <el-form-item label="openID">
               <el-input v-model="form.wechatOpenId" :disabled="readonly" maxlength="128" />
             </el-form-item>
@@ -204,14 +286,42 @@
 
     <el-dialog v-model="scenicDialogVisible" :title="scenicEditingIndex >= 0 ? '编辑景区配置' : '添加景区配置'" width="560px" destroy-on-close>
       <el-form ref="scenicFormRef" :model="scenicForm" :rules="scenicRules" label-width="86px">
-        <el-form-item label="景区名称" prop="scenicName">
-          <el-input v-model="scenicForm.scenicName" maxlength="128" />
+        <el-form-item label="景区名称" prop="scenicSpotId">
+          <el-select
+            v-model="scenicForm.scenicSpotId"
+            :loading="scenicOptionsLoading"
+            filterable
+            placeholder="请选择景区"
+            @change="selectScenic"
+          >
+            <el-option
+              v-for="scenic in scenicOptions"
+              :key="scenic.id"
+              :label="`${scenic.scenicName}(${scenic.cityName})`"
+              :value="scenic.id"
+            />
+          </el-select>
         </el-form-item>
-        <el-form-item label="城市" prop="cityName">
-          <el-input v-model="scenicForm.cityName" maxlength="64" />
+        <el-form-item label="城市">
+          <el-input :model-value="scenicForm.cityName" disabled placeholder="选择景区后自动带出" />
         </el-form-item>
-        <el-form-item label="汇合点" prop="meetingPoints">
-          <el-input v-model="scenicForm.meetingPoints" type="textarea" :rows="4" maxlength="500" show-word-limit placeholder="多个汇合点可使用逗号分隔" />
+        <el-form-item label="汇合点" prop="meetingPointNames">
+          <el-select
+            v-model="scenicForm.meetingPointNames"
+            :disabled="!scenicForm.scenicSpotId"
+            :loading="scenicDetailLoading"
+            multiple
+            collapse-tags
+            collapse-tags-tooltip
+            placeholder="请选择汇合点"
+          >
+            <el-option
+              v-for="point in meetingPointOptions"
+              :key="point.id"
+              :label="point.pointName"
+              :value="point.pointName"
+            />
+          </el-select>
         </el-form-item>
       </el-form>
       <template #footer>
@@ -250,6 +360,7 @@
 .collection-grid :deep(.el-form-item__label) { width: auto !important; color: #53657d; font-weight: 600; }
 .save-row { padding: 28px 36px; border-top: 10px solid #f4f7fb; }
 .save-row :deep(.el-button) { width: 138px; }
+.team-detail-page :deep(.el-dialog .el-select) { width: 100%; }
 @media (max-width: 1400px) {
   .basic-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
 }

--
Gitblit v1.7.1