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