lvkun996 vor 8 Monaten
Ursprung
Commit
63f4cbca1d

+ 75 - 65
src/controller/CardController.ts

@@ -111,34 +111,34 @@ export class CardController {
   }
 
   static async card21JsonById (_dataJson: API.CardJson21) {
-    const dataJson = JSON.parse(JSON.stringify({
-      header:
-      {
-        card_type: 21,
-        card_insert: { is_break: 3, music_name: 'yx3.mp3' },
-        card_remove: { is_break: 1 },
-        finish: { is_break: 3, music_name: 'wctk.mp3' },
-        grade: 1,
-        title: { is_break: 1, page: 293 }
-      },
-      game_list: [
-        // {
-        //   has_click_group: { is_break: 1, music_name: 'zzdg.mp3' },
-        //   has_click_single: { is_break: 1, music_name: 'yjdg.mp3' },
-        //   main_subject: { is_break: 3, music_name: '293tg.mp3' },
-        //   multiple_err: { is_break: 1 },
-        //   ordered_multiple_err: { is_break: 1, music_name: 'yxcw.mp3' },
-        //   rule: 7,
-        //   still_have: { is_break: 3, music_name: 'hmwc.mp3' },
-        //   touch_key: [[{ is_break: 3, value: 0 }], [{ is_break: 3, value: 0 }], [{ is_break: 3, value: 0 }]],
-        //   wait_30s: { is_break: 1, music_name: 'dtdd.mp3' },
-        //   wait_90s: { is_break: 1, music_name: 'dtdd.mp3' },
-        //   items: [{ sub_subject: { music_name: '100tg.mp3', mb: 1, ok: '', ob: 1, err: '', eb: 1 }, ok_key: [{ value: 4, music_name: '100tm2.mp3', is_break: 1, select: true }], err_key: [], ok_key_voice: {}, err_key_voice: {} }]
-        // }
-      ]
-    }))
+    // const dataJson = JSON.parse(JSON.stringify({
+    //   header: {
+    //     card_type: 21,
+    //     card_insert: { is_break: 3, music_name: 'yx3.mp3' },
+    //     card_remove: { is_break: 1 },
+    //     finish: { is_break: 3, music_name: 'wctk.mp3' },
+    //     grade: 1,
+    //     title: { is_break: 1, page: 293 }
+    //   },
+    //   game_list: [
+    //     {
+    //       has_click_group: { is_break: 1, music_name: 'zzdg.mp3' },
+    //       has_click_single: { is_break: 1, music_name: 'yjdg.mp3' },
+    //       main_subject: { is_break: 3, music_name: '293tg.mp3' },
+    //       multiple_err: { is_break: 1 },
+    //       ordered_multiple_err: { is_break: 1, music_name: 'yxcw.mp3' },
+    //       rule: 9,
+    //       still_have: { is_break: 3, music_name: 'hmwc.mp3' },
+    //       touch_key: [[{ is_break: 3, value: 0 }], [{ is_break: 3, value: 0 }], [{ is_break: 3, value: 0 }]],
+    //       wait_30s: { is_break: 1, music_name: 'dtdd.mp3' },
+    //       wait_90s: { is_break: 1, music_name: 'dtdd.mp3' },
+    //       items: [{ sub_subject: { music_name: '100tg.mp3', mb: 1, ok: '', ob: 1, err: '', eb: 1 }, ok_key: [], err_key: [], ok_key_voice: {}, err_key_voice: {} }]
+    //     }
+    //   ]
+    // }))
+    const dataJson = JSON.parse(JSON.stringify(_dataJson)) as API.CardJson21
     console.log('卡片是21时返回的参数', dataJson)
-    return { data: CardController.itemsToSteps(dataJson), cardType: dataJson.header.card_type }
+    return { data: dataJson, cardType: dataJson.header.card_type }
   }
 
   static createRectByIndex (index: number) {
@@ -185,34 +185,39 @@ export class CardController {
 
   // 把json中的steps 解析到 items下其他项
   static stepsToItems (data: API.CardJson21) {
-    console.log('解析steps', data)
-
     const newData = JSON.parse(JSON.stringify(data))
-
     newData.game_list.forEach((game: any) => {
-      if (game.rule === '7' || game.rule === 7) {
-        game.rule = 7
-        if (game.items && Array.isArray(game.items)) {
-          game.items.forEach((item: any) => {
-            if (item.steps && Array.isArray(item.steps)) {
-              item.steps.forEach((step: any, index: number) => {
-                if (step.button_key) {
-                  // 更新 ok_key
+      if (game.items && Array.isArray(game.items)) {
+        game.items.forEach((item: any) => {
+          if (item.steps && Array.isArray(item.steps)) {
+            item.steps.forEach((step: any, index: number) => {
+              step.success.forEach((childrenStep: any) => {
+                if (childrenStep.button_key) {
                   item.ok_key.push({
-                    value: step.button_key,
-                    music_name: step.audio_name,
+                    value: childrenStep.button_key,
+                    music_name: childrenStep.audio_name,
                     is_break: 1,
                     select: true
                   })
                 }
               })
-              delete item.steps
-            }
-          })
-        }
+              step.error.forEach((childrenStep: any) => {
+                if (childrenStep.button_key) {
+                  item.err_key.push({
+                    value: childrenStep.button_key,
+                    music_name: childrenStep.audio_name,
+                    is_break: 1,
+                    select: true
+                  })
+                }
+              })
+            })
+            delete item.steps
+          }
+        })
       }
     })
-
+    console.log('解析steps到Items', newData)
     return newData
   }
 
@@ -222,27 +227,32 @@ export class CardController {
     console.log('解析items', newData)
 
     newData.game_list.forEach((game: any) => {
-      if (game.rule === 7) {
-        if (game.items && Array.isArray(game.items)) {
-          game.items.forEach((item: any) => {
-            const newSteps: { button_key: number, audio_name: string, id: number }[] = []
-            if (item.ok_key && Array.isArray(item.ok_key)) {
-              // 根据 ok_key 中的 value (button_key) 排序以确保顺序
-              const sortedOkKey = [...item.ok_key].sort((a, b) => a.value - b.value)
-
-              sortedOkKey.forEach((keyItem: any) => {
-                if (keyItem.value !== undefined && keyItem.music_name !== undefined) {
-                  newSteps.push({
-                    button_key: keyItem.value,
-                    audio_name: keyItem.music_name,
-                    id: keyItem.id // 使用 keyItem 的 id 作为 step 的 id
-                  })
-                }
+      if (game.items && Array.isArray(game.items)) {
+        game.items.forEach((item: any) => {
+          const newSteps: {
+            success: { button_key: number, audio_name: string }[],
+            error: { button_key: number, audio_name: string }[]
+          } = { success: [], error: [] }
+          if (item.ok_key && Array.isArray(item.ok_key)) {
+            // 根据 ok_key 中的 value (button_key) 排序以确保顺序
+            item.ok_key.forEach((keyItem: any) => {
+              newSteps.success.push({
+                button_key: keyItem.value,
+                audio_name: keyItem.music_name
               })
-            }
-            item.steps = newSteps
-          })
-        }
+            })
+          }
+          if (item.err_key && Array.isArray(item.err_key)) {
+            // 根据 ok_key 中的 value (button_key) 排序以确保顺序
+            item.err_key.forEach((keyItem: any) => {
+              newSteps.error.push({
+                button_key: keyItem.value,
+                audio_name: keyItem.music_name
+              })
+            })
+          }
+          item.steps = newSteps
+        })
       }
     })
 

+ 3 - 2
src/pages/card/components/config-game.vue

@@ -94,7 +94,8 @@
           <div class="card-config-content">
             <gameStage3
               v-if="cardJson.game_list[currentGameIndex]?.items?.[currentSubFolderIndex]"
-              v-model="cardJson.game_list[currentGameIndex].items[currentSubFolderIndex].steps"
+              v-model="cardJson.game_list[currentGameIndex].items[currentSubFolderIndex]"
+              :rule="cardJson.game_list[currentGameIndex].rule"
               @update:modelValue="changedSteps"
               @step-selected="emits('step-selected', $event)"
             />
@@ -277,7 +278,7 @@ const editForm = reactive({
 const subItemModalVisible = ref(false)
 const subItemForm = reactive({
   sub_subject: {
-    music_name: '102.mp3',
+    music_name: '',
     mb: '',
     ok: '',
     ob: '',

+ 233 - 100
src/pages/card/components/game-stage-3.vue

@@ -1,63 +1,125 @@
 <template>
   <div class="game-stage-3">
-    <div class="header">
-      <a-button type="primary" size="small" @click="showAddStepModal">
-        <template #icon><plus-outlined /></template>
-        新增步骤
-      </a-button>
-    </div>
-
-    <VueDraggableNext
-      :list="steps"
-      group="people"
-      item-key="id"
-      :animation="300"
-      @end="onDragEnd"
-    >
-      <div v-for="(element, index) in steps" :key="element.id" class="step-item-wrapper">
-        <div
-          class="step-item"
-          :class="{ 'step-item-active': activeStepIndex === index }"
-          @click="selectStep(index)"
-        >
-          <div class="step-info">
-            <span class="step-number">步骤 {{ index + 1 }}</span>
-            <div class="step-details">
-              <span>按钮: <strong>{{ getButtonLabel(element.button_key) }}</strong></span>
-              <span>音频: <strong>{{ element.audio_name }}</strong></span>
+    <div class="step-list" >
+      <a-row  style="width: 100%">
+        <a-col :span="24" style="margin-bottom: 16px">
+          <a-space>
+            <div class="step-title" >正确按钮</div>
+            <a-button type="primary" size="small" @click="showAddStepModal('success')"> 新增 </a-button>
+
+          </a-space>
+        </a-col>
+     </a-row>
+      <VueDraggableNext
+        :list="steps.ok_key"
+        group="people"
+        item-key="id"
+        :animation="300"
+        @end="onDragEnd"
+      >
+        <div v-for="(element, index) in steps.ok_key" :key="index" class="step-item-wrapper">
+          <div
+            class="step-item"
+            :class="{ 'step-item-active': activeStepIndex === element.value }"
+            @click="selectStep(element.value)"
+          >
+            <div class="step-info">
+              <span class="step-number">按钮 {{ index + 1 }}</span>
+              <div class="step-details">
+                <span>按钮: <strong>{{ getButtonLabel(element.value) }}</strong></span>
+                <span>音频: <strong>{{ element.music_name }}</strong></span>
+              </div>
+            </div>
+            <div class="step-actions">
+              <a-popconfirm
+                title="确定要删除这个步骤吗?"
+                ok-text="确定"
+                cancel-text="取消"
+                @confirm.stop="deleteGameStep(index, 'ok_key')"
+
+                @cancel.stop
+              >
+                <delete-outlined @click.stop />
+              </a-popconfirm>
             </div>
           </div>
-          <div class="step-actions">
-            <a-popconfirm
-              title="确定要删除这个步骤吗?"
-              ok-text="确定"
-              cancel-text="取消"
-              @confirm.stop="deleteGameStep(index)"
-              @cancel.stop
-            >
-              <delete-outlined @click.stop />
-            </a-popconfirm>
+        </div>
+      </VueDraggableNext>
+      <a-empty v-if="steps.ok_key.length === 0" description="暂无正确按钮,请点击新增按钮" />
+
+    </div>
+    <div class="step-list" >
+      <a-row  style="width: 100%">
+      <a-col :span="24" style="margin-bottom: 16px">
+        <a-space>
+          <div class="step-title" >错误按钮</div>
+          <a-button type="primary" size="small" @click="showAddStepModal('error')"> 新增</a-button>
+        </a-space>
+      </a-col>
+      </a-row>
+      <VueDraggableNext
+        :list="steps.err_key"
+        group="people"
+        item-key="id"
+        :animation="300"
+        @end="onDragEnd"
+      >
+        <div v-for="(element, index) in steps.err_key" :key="index" class="step-item-wrapper">
+          <div
+            class="step-item"
+            :class="{ 'step-item-active': activeStepIndex === element.value }"
+            @click="selectStep(element.value)"
+          >
+            <div class="step-info">
+              <span class="step-number">按钮 {{ index + 1 }}</span>
+              <div class="step-details">
+                <span>按钮: <strong>{{ getButtonLabel(element.value) }}</strong></span>
+                <span>音频: <strong>{{ element.music_name }}</strong></span>
+              </div>
+            </div>
+            <div class="step-actions">
+              <a-popconfirm
+                title="确定要删除这个步骤吗?"
+                ok-text="确定"
+                cancel-text="取消"
+                @confirm.stop="deleteGameStep(index, 'err_key')"
+
+                @cancel.stop
+              >
+                <delete-outlined @click.stop />
+              </a-popconfirm>
+            </div>
           </div>
         </div>
-      </div>
-    </VueDraggableNext>
-    <!-- <a-empty v-else description="暂无步骤,请点击新增步骤" /> -->
+      </VueDraggableNext>
+      <a-empty v-if="steps.err_key.length === 0" description="暂无错误按钮,请点击新增按钮" />
+
+    </div>
 
     <a-modal
       v-model:open="addStepModalVisible"
-      title="新增步骤"
       width="600px"
+      :closable="false"
       @ok="handleAddStep"
       @cancel="cancelAddStep"
       wrap-class-name="game-stage-3-modal"
     >
-      <a-form :model="newStepForm" layout="vertical">
+      <template #title>
+        <div class="header">
+          <span>新增步骤</span>
+          <a-radio-group v-if="props.rule === 9" v-model:value="btnMode">
+            <a-radio-button value="success">正确</a-radio-button>
+            <a-radio-button value="error">错误</a-radio-button>
+          </a-radio-group>
+        </div>
+      </template>
+      <a-form :model="steps.ok_key" layout="vertical" v-if="btnMode === 'success'">
         <a-form-item label="选择按钮">
           <div class="button-grid">
             <a-button
               v-for="btn in buttonOptions"
               :key="btn.value"
-              :type="newStepForm.button_key === btn.value ? 'primary' : 'default'"
+              :type="getBtnTypeByKey(btn.value)"
               @click="selectButton(btn)"
             >
               {{ btn.label }}
@@ -65,10 +127,43 @@
           </div>
         </a-form-item>
         <a-form-item label="选择语音">
-          <SelectAudioNew
-            v-model="newStepForm.audio_name"
-            placeholder="请选择步骤语音"
-          />
+          <span
+            style="mergin-bottom: 8px;"
+            :key="item.value"
+             v-for="item in steps.ok_key"
+          >
+            <SelectAudioNew
+              v-model="item.music_name"
+              placeholder="请选择步骤语音"
+            />
+          </span>
+        </a-form-item>
+      </a-form>
+      <a-form :model="steps.err_key" layout="vertical" v-else>
+        <a-form-item label="选择按钮">
+          <div class="button-grid">
+            <a-button
+              v-for="btn in buttonOptions"
+              :key="btn.value"
+              danger
+              :type="getBtnTypeByKey(btn.value)"
+              @click="selectButton(btn)"
+            >
+              {{ btn.label }}
+            </a-button>
+          </div>
+        </a-form-item>
+        <a-form-item label="选择语音">
+          <span
+            style="mergin-bottom: 8px;"
+            v-for="item in steps.err_key"
+            :key="item.value"
+          >
+            <SelectAudioNew
+              v-model="item.music_name"
+              placeholder="请选择步骤语音"
+            />
+          </span>
         </a-form-item>
       </a-form>
     </a-modal>
@@ -76,22 +171,36 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, computed, reactive } from 'vue'
+import { ref, computed, reactive, watch } from 'vue'
 import { PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue'
 import { VueDraggableNext } from 'vue-draggable-next'
 import SelectAudioNew from './select-audio-new.vue'
 import { message } from 'ant-design-vue'
 
 interface Step {
-  id: number;
-  button_key: number;
-  audio_name: string;
+  success: {
+    button_key: number;
+    audio_name: string;
+  }[]
+  error: {
+    button_key: number;
+    audio_name: string;
+  }[]
 }
 
 interface Props {
-  modelValue: Step[]
+  modelValue: API.CardJson21Item,
+  rule: API.Rule
 }
 
+watch(
+  () => props.rule,
+  (newVal) => {
+    console.log('Rule 的改变:', props.rule)
+  },
+  { immediate: true }
+)
+
 const props = defineProps<Props>()
 const emits = defineEmits(['update:modelValue', 'step-selected'])
 
@@ -103,11 +212,13 @@ const steps = computed({
 const addStepModalVisible = ref(false)
 const activeStepIndex = ref<number | null>(null)
 
-const newStepForm = reactive({
-  button_key: null as number | null,
-  audio_name: ''
+const newStepForm = reactive<Step>({
+  success: [],
+  error: []
 })
 
+const btnMode = ref<'success' | 'error'>('success')
+
 const buttonOptions = (() => {
   const options: {label: string, value: number}[] = []
   const letters = ['A', 'B', 'C', 'D', 'E', 'F']
@@ -127,43 +238,55 @@ const buttonOptions = (() => {
 const buttonMap = new Map<number, string>(buttonOptions.map(opt => [opt.value, opt.label]))
 const getButtonLabel = (value: number) => buttonMap.get(value) || '未知'
 
-const showAddStepModal = () => {
-  resetNewStepForm()
+const getBtnTypeByKey = (key: number) => {
+  if (steps.value.ok_key.some(item => item.value === key)) {
+    return 'primary'
+  } else if (steps.value.err_key.some(item => item.value === key)) {
+    return 'dashed'
+  }
+  return 'default'
+}
+
+const showAddStepModal = (mode: 'success' | 'error') => {
+  btnMode.value = mode
   addStepModalVisible.value = true
 }
 
 const selectButton = (btn: { label: string, value: number }) => {
-  newStepForm.button_key = btn.value
+  if (btnMode.value === 'success') {
+    if (props.rule === 7) {
+      steps.value.ok_key[0] = { value: btn.value, music_name: '', is_break: 1 }
+    } else {
+      steps.value.ok_key.push({ value: btn.value, music_name: '', is_break: 1 })
+    }
+  } else {
+    steps.value.err_key.push({ value: btn.value, music_name: '', is_break: 1 })
+  }
 }
 
 const handleAddStep = () => {
-  if (newStepForm.button_key === null) {
-    message.error('请选择一个按钮')
-    return
-  }
-  if (!newStepForm.audio_name) {
-    message.error('请选择一个语音')
+  if (props.rule === 7 && steps.value.ok_key.length === 0) {
+    message.error('请至少选择一个正确按钮')
     return
-  }
+  } else {
+    for (let index = 0; index < steps.value.ok_key.length; index++) {
+      const item = steps.value.ok_key[index]
+      if (!item.music_name) {
+        message.error('请选择语音')
+        return
+      }
+    }
 
-  const newStep = {
-    id: Date.now(),
-    button_key: newStepForm.button_key,
-    audio_name: newStepForm.audio_name
+    for (let index = 0; index < steps.value.err_key.length; index++) {
+      const item = steps.value.err_key[index]
+      if (!item.music_name) {
+        message.error('请选择语音')
+        return
+      }
+    }
   }
 
-  const ok_key = { value: newStep.button_key, is_break: 1, music_name: '' }
-
-  const ok_key_voice = { music_name: newStep.audio_name, is_break: 1, value: newStep.button_key }
-
-  // steps.value.ok_key.push(ok_key)
-  // steps.value.ok_key_voice.push(ok_key_voice)
-
-  console.log('steps.value:', steps.value)
-
-  const newSteps = [...(steps.value || []), newStep]
-
-  emits('update:modelValue', newSteps)
+  emits('update:modelValue', steps.value)
 
   addStepModalVisible.value = false
 }
@@ -172,14 +295,9 @@ const cancelAddStep = () => {
   addStepModalVisible.value = false
 }
 
-const resetNewStepForm = () => {
-  newStepForm.button_key = null
-  newStepForm.audio_name = ''
-}
-
-const deleteGameStep = (index: number) => {
+const deleteGameStep = (index: number, key: 'ok_key' | 'err_key') => {
   if (steps.value) {
-    steps.value.splice(index, 1)
+    steps.value[key].splice(index, 1)
     emits('update:modelValue', steps.value)
     if (activeStepIndex.value === index) {
       activeStepIndex.value = null
@@ -188,11 +306,11 @@ const deleteGameStep = (index: number) => {
   }
 }
 
-const selectStep = (index: number) => {
-  activeStepIndex.value = index
-  if (steps.value && steps.value[index]) {
-    emits('step-selected', steps.value[index].button_key)
-  }
+const selectStep = (value: number) => {
+  activeStepIndex.value = value
+  // if (steps.value && steps.value[index]) {
+  //   emits('step-selected', steps.value[index].button_key)
+  // }
 }
 
 const onDragEnd = () => {
@@ -215,6 +333,7 @@ const onDragEnd = () => {
   }
 
   .step-item {
+    width: 100%;
     display: flex;
     align-items: center;
     justify-content: space-between;
@@ -269,15 +388,29 @@ const onDragEnd = () => {
 
 }
 </style>
-<style lang="less">
-.game-stage-3-modal .button-grid {
-  display: grid;
-  grid-template-columns: repeat(6, 1fr);
-  gap: 10px;
-  padding: 16px;
-  border-radius: 6px;
-  background-color: #f7f7f7;
-  border: 1px solid #e8e8e8;
+<style lang="less" scoped>
+.step-list {
+  width: 100%;
+  margin-bottom: 24px;
+  .step-title {
+    // margin-bottom: 24px;
+  }
+}
+.game-stage-3-modal {
+  .header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+  .button-grid {
+    display: grid;
+    grid-template-columns: repeat(6, 1fr);
+    gap: 10px;
+    padding: 16px;
+    border-radius: 6px;
+    background-color: #f7f7f7;
+    border: 1px solid #e8e8e8;
+  }
 }
 
 .game-stage-3-modal .button-grid .ant-btn {

+ 2 - 0
src/typeing.d.ts

@@ -276,6 +276,8 @@ declare namespace API {
     }
   }
 
+  type CardJson21Item = CardJson21['game_list'][0]['items'][0]
+
   interface CardJson21 {
     'header': {
         'card_type': number,