|
@@ -0,0 +1,347 @@
|
|
|
+<template>
|
|
|
+ <div class="p-2">
|
|
|
+ <el-card shadow="never">
|
|
|
+ <template #header>
|
|
|
+ <div class="flex items-center justify-between">
|
|
|
+ <div class="text-lg font-600">
|
|
|
+ 赛事文章编辑
|
|
|
+ <!-- - {{ pageTitle }} -->
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <el-button @click="handleBack">返回</el-button>
|
|
|
+ <el-button type="primary" @click="handleSaveArticle" :loading="saving">保存</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div>
|
|
|
+ <el-alert
|
|
|
+ v-if="!articleDialog.currentEventId"
|
|
|
+ title="缺少赛事ID,无法编辑文章"
|
|
|
+ type="error"
|
|
|
+ show-icon
|
|
|
+ class="mb-2"
|
|
|
+ />
|
|
|
+ <el-tabs v-model="activeTab" @tab-click="handleTabClick">
|
|
|
+ <el-tab-pane label="竞赛流程" name="competition-process">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.competitionProcess.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.competitionProcess.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.competitionProcess.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="竞赛项目" name="competition-items">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.competitionItems.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.competitionItems.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.competitionItems.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="活动议程" name="activity-agenda">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.activityAgenda.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.activityAgenda.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.activityAgenda.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="项目介绍" name="project-introduction">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.projectIntroduction.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.projectIntroduction.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.projectIntroduction.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="竞赛流程" name="competition-flow">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.competitionFlow.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.competitionFlow.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.competitionFlow.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="赛事分组" name="event-grouping">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.eventGrouping.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.eventGrouping.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.eventGrouping.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="运动员号码簿" name="athlete-handbook">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.athleteHandbook.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.athleteHandbook.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.athleteHandbook.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="项目场地" name="project-venue">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.projectVenue.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.projectVenue.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.projectVenue.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="交通指示" name="traffic-guide">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.trafficGuide.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.trafficGuide.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.trafficGuide.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="快捷报名" name="quick-registration">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.quickRegistration.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.quickRegistration.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.quickRegistration.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+
|
|
|
+ <el-tab-pane label="报名咨询" name="registration-consultation">
|
|
|
+ <div class="article-form">
|
|
|
+ <el-form-item label="标题">
|
|
|
+ <el-input v-model="articleData.registrationConsultation.title" placeholder="请输入标题" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="内容">
|
|
|
+ <Editor v-model="articleData.registrationConsultation.content" :min-height="300" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="备注">
|
|
|
+ <el-input v-model="articleData.registrationConsultation.remark" placeholder="请输入备注" type="textarea" :rows="3" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-tab-pane>
|
|
|
+ </el-tabs>
|
|
|
+ </div>
|
|
|
+ </el-card>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <script setup lang="ts" name="GameEventArticleEditor">
|
|
|
+ import { useRouter, useRoute } from 'vue-router';
|
|
|
+ import { ref, reactive, onMounted } from 'vue';
|
|
|
+ import Editor from '@/components/Editor/index.vue';
|
|
|
+ import { getEventMdByEventAndType, editEventMd } from '@/api/system/eventMd';
|
|
|
+ import type { EventMdForm } from '@/api/system/eventMd/types';
|
|
|
+ import { useGameEventStore } from '@/store/modules/gameEvent';
|
|
|
+ import { storeToRefs } from 'pinia';
|
|
|
+
|
|
|
+ const router = useRouter();
|
|
|
+ const route = useRoute();
|
|
|
+
|
|
|
+ //从pinia中获取默认赛事信息
|
|
|
+ const gameEventStore = useGameEventStore();
|
|
|
+ const { defaultEventInfo } = storeToRefs(gameEventStore);
|
|
|
+
|
|
|
+ const pageTitle = ref<string>('');
|
|
|
+ const saving = ref<boolean>(false);
|
|
|
+
|
|
|
+ const articleDialog = reactive({
|
|
|
+ currentEventId: defaultEventInfo.value.eventId,
|
|
|
+ });
|
|
|
+
|
|
|
+ const activeTab = ref('competition-process');
|
|
|
+
|
|
|
+ const tabTypeMapping: Record<string, number> = {
|
|
|
+ 'competition-process': 1,
|
|
|
+ 'competition-items': 2,
|
|
|
+ 'activity-agenda': 3,
|
|
|
+ 'project-introduction': 4,
|
|
|
+ 'competition-flow': 5,
|
|
|
+ 'event-grouping': 6,
|
|
|
+ 'athlete-handbook': 7,
|
|
|
+ 'project-venue': 8,
|
|
|
+ 'traffic-guide': 9,
|
|
|
+ 'quick-registration': 10,
|
|
|
+ 'registration-consultation': 11
|
|
|
+ };
|
|
|
+
|
|
|
+ const articleData = reactive({
|
|
|
+ competitionProcess: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ competitionItems: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ activityAgenda: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ projectIntroduction: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ competitionFlow: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ eventGrouping: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ athleteHandbook: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ projectVenue: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ trafficGuide: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ quickRegistration: { id: undefined as number | undefined, title: '', content: '', remark: '' },
|
|
|
+ registrationConsultation: { id: undefined as number | undefined, title: '', content: '', remark: '' }
|
|
|
+ });
|
|
|
+
|
|
|
+ const getDataKeyByTabName = (tabName: string): keyof typeof articleData | null => {
|
|
|
+ const mapping: Record<string, keyof typeof articleData> = {
|
|
|
+ 'competition-process': 'competitionProcess',
|
|
|
+ 'competition-items': 'competitionItems',
|
|
|
+ 'activity-agenda': 'activityAgenda',
|
|
|
+ 'project-introduction': 'projectIntroduction',
|
|
|
+ 'competition-flow': 'competitionFlow',
|
|
|
+ 'event-grouping': 'eventGrouping',
|
|
|
+ 'athlete-handbook': 'athleteHandbook',
|
|
|
+ 'project-venue': 'projectVenue',
|
|
|
+ 'traffic-guide': 'trafficGuide',
|
|
|
+ 'quick-registration': 'quickRegistration',
|
|
|
+ 'registration-consultation': 'registrationConsultation'
|
|
|
+ };
|
|
|
+ return mapping[tabName] || null;
|
|
|
+ };
|
|
|
+
|
|
|
+ const loadTabData = async (tabName: string) => {
|
|
|
+ const type = tabTypeMapping[tabName];
|
|
|
+ if (articleDialog.currentEventId && type) {
|
|
|
+ try {
|
|
|
+ const response = await getEventMdByEventAndType(articleDialog.currentEventId, type);
|
|
|
+ const eventMd = response.data;
|
|
|
+ const dataKey = getDataKeyByTabName(tabName);
|
|
|
+ if (dataKey && articleData[dataKey]) {
|
|
|
+ if (eventMd) {
|
|
|
+ articleData[dataKey].id = typeof eventMd.id === 'number' ? eventMd.id : Number(eventMd.id);
|
|
|
+ articleData[dataKey].title = eventMd.title || '';
|
|
|
+ articleData[dataKey].content = eventMd.content || '';
|
|
|
+ articleData[dataKey].remark = eventMd.remark || '';
|
|
|
+ } else {
|
|
|
+ articleData[dataKey].id = undefined;
|
|
|
+ articleData[dataKey].title = '';
|
|
|
+ articleData[dataKey].content = '';
|
|
|
+ articleData[dataKey].remark = '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch {
|
|
|
+ const dataKey = getDataKeyByTabName(tabName);
|
|
|
+ if (dataKey && articleData[dataKey]) {
|
|
|
+ articleData[dataKey].id = undefined;
|
|
|
+ articleData[dataKey].title = '';
|
|
|
+ articleData[dataKey].content = '';
|
|
|
+ articleData[dataKey].remark = '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleTabClick = async (tab: any) => {
|
|
|
+ const tabName = tab.props.name;
|
|
|
+ await loadTabData(tabName);
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSaveArticle = async () => {
|
|
|
+ if (!articleDialog.currentEventId) {
|
|
|
+ ElMessage.error('赛事ID不能为空');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const currentTabName = activeTab.value;
|
|
|
+ const type = tabTypeMapping[currentTabName];
|
|
|
+ const dataKey = getDataKeyByTabName(currentTabName);
|
|
|
+ if (!dataKey || !articleData[dataKey]) {
|
|
|
+ ElMessage.error('获取当前标签页数据失败');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const currentData = articleData[dataKey];
|
|
|
+ if (!currentData.title?.trim()) {
|
|
|
+ ElMessage.error('标题不能为空');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ saving.value = true;
|
|
|
+ const formData: EventMdForm = {
|
|
|
+ id: currentData.id,
|
|
|
+ eventId: articleDialog.currentEventId,
|
|
|
+ title: currentData.title,
|
|
|
+ content: currentData.content || '',
|
|
|
+ type: type,
|
|
|
+ remark: currentData.remark || ''
|
|
|
+ };
|
|
|
+ await editEventMd(formData);
|
|
|
+ ElMessage.success('文章保存成功');
|
|
|
+ await loadTabData(currentTabName);
|
|
|
+ } catch {
|
|
|
+ ElMessage.error('保存文章失败');
|
|
|
+ } finally {
|
|
|
+ saving.value = false;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleBack = () => {
|
|
|
+ router.back();
|
|
|
+ };
|
|
|
+
|
|
|
+ onMounted(async () => {
|
|
|
+ const eventId = defaultEventInfo.value.eventId;
|
|
|
+ // const eventIdParam = route.params.eventId as string | undefined;
|
|
|
+ articleDialog.currentEventId = eventId;
|
|
|
+ // pageTitle.value = eventIdParam ? `赛事ID: ${eventIdParam}` : '未指定赛事';
|
|
|
+ // 初次进入加载默认标签页
|
|
|
+ await loadTabData(activeTab.value);
|
|
|
+ });
|
|
|
+ </script>
|
|
|
+
|
|
|
+ <style scoped>
|
|
|
+ .article-form {
|
|
|
+ padding: 10px 6px;
|
|
|
+ }
|
|
|
+ </style>
|