| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889 |
- <template>
- <modal-pro
- :label="getModalTitle()"
- :open="open"
- :mask="false"
- width="540px"
- @close="emits('update:open', false)"
- @ok="saveGameConfig"
- styles="position: fixed;top: 60px;right: 90px; pointer-events: none;"
- >
- <template #title>
- <div style="display: flex;justify-content: space-between;" >
- <div>游戏配置</div>
- <a-button v-if="currentLevel === 0" type="primary" size="small" @click="createGameOne">
- <template #icon><plus-outlined /></template>
- 新增
- </a-button>
- </div>
- </template>
- <div class="config-game-page">
- <div class="game-modal-content">
- <!-- 显示返回按钮和新增按钮,仅在非顶级目录显示 -->
- <div v-if="currentLevel > 0" class="back-button-row">
- <a-button type="link" @click="goBack">
- <template #icon><left-outlined /></template>
- 返回上级
- </a-button>
- <a-button v-if="currentLevel === 1" type="primary" size="small" @click="createSubItem">
- <template #icon><plus-outlined /></template>
- 新增
- </a-button>
- </div>
- <!-- 顶级文件夹内容 -->
- <a-row v-if="currentLevel === 0" justify="flex-start" :gutter="[8, 8]" class="config-game-list">
- <a-col
- :span="7"
- style="height: 120px;"
- class="config-game-item"
- v-for="(folder, index) in cardJson.game_list"
- :key="index"
- @dblclick="enterFolder(index)"
- >
- <!-- 状态图标 -->
- <div class="status-icon">
- <CheckCircleFilled v-if="validateGameConfig(folder).isValid" class="status-complete" />
- <ExclamationCircleFilled v-else class="status-incomplete" />
- </div>
- <img class="folder-icon" :src="require('@/assets/common/folder.svg')" alt="">
- <div class="folder-footer">
- <div>游戏 {{ index + 1 }}</div>
- <div>
- <a-dropdown :trigger="['hover']">
- <SmallDashOutlined class="action-icon" />
- <template #overlay>
- <a-menu>
- <a-menu-item key="edit" @click="handleEdit(index)">
- <EditOutlined />
- <span style="margin-left: 8px;">编辑</span>
- </a-menu-item>
- <a-menu-item key="delete" @click="handleDelete(index)">
- <DeleteOutlined style="color: #ff4d4f;" />
- <span style="margin-left: 8px;">删除</span>
- </a-menu-item>
- </a-menu>
- </template>
- </a-dropdown>
- </div>
- </div>
- </a-col>
- <a-empty style="margin: 0 auto;" v-if="cardJson.game_list.length === 0" description="暂无游戏"> </a-empty>
- </a-row>
- <div v-else-if="currentLevel === 1">
- <a-row class="config-game-list" :gutter="[8, 8]">
- <VueDraggableNext
- :list="cardJson.game_list[currentGameIndex].items"
- group="people"
- item-key="id"
- :animation="300"
- class="config-game-list"
- >
- <a-col
- :span="10"
- class="config-game-item"
- v-for="(item, index) in cardJson.game_list[currentGameIndex].items"
- :key="index"
- @dblclick="enterCardConfig(index)"
- >
- <img class="folder-icon" :src="require('@/assets/common/folder.svg')" alt="">
- <div class="folder-info">
- <div v-if="item.sub_subject?.music_name" class="music-badge">
- <sound-outlined />
- <span class="music-name">{{ item.sub_subject.music_name }}</span>
- </div>
- </div>
- <div class="folder-footer">
- <div>游戏 {{ index + 1 }}</div>
- <div>
- <a-dropdown :trigger="['hover']">
- <SmallDashOutlined class="action-icon" />
- <template #overlay>
- <a-menu>
- <a-menu-item key="edit" @click="handleEditSubItem(index)">
- <EditOutlined />
- <span style="margin-left: 8px;">编辑</span>
- </a-menu-item>
- <a-menu-item key="delete" @click="handleDeleteSubItem(index)">
- <DeleteOutlined style="color: #ff4d4f;" />
- <span style="margin-left: 8px;">删除</span>
- </a-menu-item>
- </a-menu>
- </template>
- </a-dropdown>
- </div>
- </div>
- </a-col>
- </VueDraggableNext>
- </a-row>
- <a-empty style="margin: 0 auto;" v-if="cardJson.game_list[currentGameIndex].items.length === 0" description="暂无游戏"> </a-empty>
- </div>
- <!-- 三级内容:游戏步骤配置 -->
- <div v-else-if="currentLevel === 2">
- <div class="card-config-content">
- <gameStage3
- v-if="cardJson.game_list[currentGameIndex]?.items?.[currentSubFolderIndex]"
- v-model="cardJson.game_list[currentGameIndex].items[currentSubFolderIndex]"
- :rule="cardJson.game_list[currentGameIndex].rule"
- @update:modelValue="changedSteps"
- @step-selected="emits('step-selected', $event)"
- />
- </div>
- </div>
- </div>
- </div>
- </modal-pro>
- <!-- 新增子项目弹窗 -->
- <a-modal
- v-model:open="subItemModalVisible"
- title="新增子项目"
- width="400px"
- @ok="handleSaveSubItem"
- >
- <a-form :model="subItemForm" layout="vertical">
- <a-form-item label="子主题音乐">
- <SelectAudioNew
- v-model="subItemForm.sub_subject.music_name"
- placeholder="请选择子主题音乐"
- />
- <!-- 已选择的音乐名称展示区域 -->
- <div v-if="subItemForm.sub_subject.music_name" class="selected-music-display">
- <div class="music-info">
- <sound-outlined />
- <span class="music-name">{{ subItemForm.sub_subject.music_name }}</span>
- </div>
- </div>
- </a-form-item>
- </a-form>
- </a-modal>
- <!-- 编辑子项目弹窗 -->
- <a-modal
- v-model:open="editSubItemModalVisible"
- title="编辑子项目"
- width="400px"
- @ok="handleSaveSubItemEdit"
- @cancel="handleCancelSubItemEdit"
- >
- <a-form :model="editSubItemForm" layout="vertical">
- <a-form-item label="子主题音乐">
- <SelectAudioNew
- v-model="editSubItemForm.sub_subject.music_name"
- placeholder="请选择子主题音乐"
- />
- <!-- 已选择的音乐名称展示区域 -->
- <div v-if="editSubItemForm.sub_subject.music_name" class="selected-music-display">
- <div class="music-info">
- <sound-outlined />
- <span class="music-name">{{ editSubItemForm.sub_subject.music_name }}</span>
- </div>
- </div>
- </a-form-item>
- </a-form>
- </a-modal>
- <!-- 编辑游戏弹窗 -->
- <a-modal
- v-model:open="editModalVisible"
- title="编辑游戏配置"
- width="600px"
- @ok="handleSaveEdit"
- @cancel="handleCancelEdit"
- >
- <a-form :model="editForm" layout="vertical">
- <!-- 规则单独一行 -->
- <a-form-item label="规则">
- <a-select v-model:value="editForm.rule" placeholder="请选择规则">
- <a-select-option v-for="rule in ruleOptions" :key="rule.value" :value="rule.value">
- {{ rule.title }}
- </a-select-option>
- </a-select>
- </a-form-item>
- <!-- 音频选择器两列布局 -->
- <a-row :gutter="16">
- <a-col :span="12">
- <a-form-item label="主题音乐:">
- <SelectAudioNew
- v-model="editForm.mainSubject.music_name"
- placeholder="请选择主题音乐"
- />
- </a-form-item>
- </a-col>
- <a-col :span="12">
- <a-form-item label="顺序多选错误音乐:">
- <SelectAudioNew
- v-model="editForm.ordered_multiple_err.music_name"
- placeholder="请选择顺序多选错误音乐"
- />
- </a-form-item>
- </a-col>
- </a-row>
- <a-row :gutter="16">
- <a-col :span="12">
- <a-form-item label="重复单击音乐:">
- <SelectAudioNew
- v-model="editForm.has_click_single.music_name"
- placeholder="请选择重复点击音乐"
- />
- </a-form-item>
- </a-col>
- <a-col :span="12">
- <a-form-item label="再次点击音乐:">
- <SelectAudioNew
- v-model="editForm.still_have.music_name"
- placeholder="请选择再次点击音乐"
- />
- </a-form-item>
- </a-col>
- </a-row>
- <a-row :gutter="16">
- <a-col :span="12">
- <a-form-item label="重复组点击音乐:">
- <SelectAudioNew
- v-model="editForm.has_click_group.music_name"
- placeholder="请选择重复组点击音乐乐"
- />
- </a-form-item>
- </a-col>
- <a-col :span="12">
- <a-form-item label="等待30秒音乐:">
- <SelectAudioNew
- v-model="editForm.wait_30s.music_name"
- placeholder="请选择等待30秒音乐"
- />
- </a-form-item>
- </a-col>
- </a-row>
- <a-row :gutter="16">
- <a-col :span="12">
- <a-form-item label="等待90秒音乐:">
- <SelectAudioNew
- v-model="editForm.wait_90s.music_name"
- placeholder="请选择等待90秒音乐"
- />
- </a-form-item>
- </a-col>
- <a-col :span="12">
- <!-- 空列,保持对称 -->
- </a-col>
- </a-row>
- </a-form>
- </a-modal>
- </template>
- <script lang='ts' setup>
- import { CardController } from '@/controller'
- import { LeftOutlined, PlusOutlined, SmallDashOutlined, EditOutlined, DeleteOutlined, CheckCircleFilled, ExclamationCircleFilled, SoundOutlined } from '@ant-design/icons-vue'
- import { reactive, ref, PropType, computed, watch } from 'vue'
- import { message } from 'ant-design-vue'
- import SelectAudioNew from './select-audio-new.vue'
- import gameStage3 from './game-stage-3.vue'
- import { VueDraggableNext } from 'vue-draggable-next'
- const props = defineProps({
- open: {
- type: Boolean,
- default: false
- },
- config: {
- type: Object as PropType<API.CardJson21>,
- default: () => ({})
- }
- })
- const emits = defineEmits(['update:open', 'step-selected', 'update:config'])
- // 卡片category为21的json
- const cardJson = computed({
- get: () => props.config,
- set: (value) => emits('update:config', value)
- })
- // 一级folders的form
- const game1FormJson = {
- rule: '',
- main_subject: { music_name: '', is_break: 1 },
- ordered_multiple_err: { music_name: '', is_break: 1 },
- has_click_single: { music_name: '', is_break: 1 },
- still_have: { music_name: '', is_break: 1 },
- has_click_group: { music_name: '', is_break: 1 },
- wait_30s: { music_name: '', is_break: 1 },
- wait_90s: { music_name: '', is_break: 1 }
- }
- // 当前层级:0表示顶级文件夹,1表示sub文件夹,2表示游戏配置
- const currentLevel = ref(0)
- // 规则下拉选项
- const ruleOptions = CardController.ruleList
- // 编辑弹窗相关
- const editModalVisible = ref(false)
- const editingIndex = ref(-1)
- const editForm = reactive({
- rule: '',
- mainSubject: { music_name: '', is_break: 1 },
- ordered_multiple_err: { music_name: '', is_break: 1 },
- has_click_single: { music_name: '', is_break: 1 },
- still_have: { music_name: '', is_break: 1 },
- has_click_group: { music_name: '', is_break: 1 },
- wait_30s: { music_name: '', is_break: 1 },
- wait_90s: { music_name: '', is_break: 1 }
- })
- // 编辑子项目弹窗相关
- const editSubItemModalVisible = ref(false)
- const editingSubItemIndex = ref(-1)
- const editSubItemForm = reactive({
- sub_subject: {
- music_name: '',
- mb: '',
- ok: '',
- ob: '',
- err: '',
- eb: ''
- },
- ok_key: [],
- err_key: [],
- ok_key_voice: {},
- err_key_voice: {}
- })
- // 子项目弹窗相关
- const subItemModalVisible = ref(false)
- const subItemForm = reactive({
- sub_subject: {
- music_name: '',
- mb: '',
- ok: '',
- ob: '',
- err: '',
- eb: ''
- },
- ok_key: [],
- err_key: [],
- ok_key_voice: {},
- err_key_voice: {}
- })
- // 当前选中的游戏索引
- const currentGameIndex = ref(0)
- // 当前选中的子文件夹索引
- const currentSubFolderIndex = ref(0)
- // 获取弹窗标题
- const getModalTitle = () => {
- switch (currentLevel.value) {
- case 0:
- return '游戏配置'
- case 1:
- return '游戏配置'
- case 2:
- return '游戏配置'
- default:
- return '游戏配置'
- }
- }
- const createGameOne = () => {
- cardJson.value.game_list.push(JSON.parse(JSON.stringify(game1FormJson)))
- }
- // 校验游戏配置是否完整
- const validateGameConfig = (gameConfig: any) => {
- const requiredFields = [
- 'rule',
- 'main_subject.music_name',
- 'ordered_multiple_err.music_name',
- 'has_click_single.music_name',
- 'still_have.music_name',
- 'has_click_group.music_name',
- 'wait_30s.music_name',
- 'wait_90s.music_name'
- ]
- const missingFields: string[] = []
- requiredFields.forEach(field => {
- const fieldParts = field.split('.')
- let value = gameConfig
- for (const part of fieldParts) {
- value = value?.[part]
- }
- if (!value || value === '') {
- missingFields.push(field)
- }
- })
- return {
- isValid: missingFields.length === 0,
- missingFields
- }
- }
- // 进入二级文件夹
- const enterFolder = (index: number) => {
- const gameConfig = cardJson.value.game_list[index]
- const validation = validateGameConfig(gameConfig)
- if (!validation.isValid) {
- const fieldNames = {
- rule: '规则',
- 'mainSubject.music_name': '主题音乐',
- 'ordered_multiple_err.music_name': '顺序多选错误音乐',
- 'has_click_single.music_name': '重复单击音乐',
- 'still_have.music_name': '再次点击音乐',
- 'has_click_group.music_name': '重复组点击音乐',
- 'wait_30s.music_name': '等待30秒音乐',
- 'wait_90s.music_name': '等待90秒音乐'
- }
- const missingFieldNames = validation.missingFields.map(field => fieldNames[field] || field)
- // 使用 Ant Design 的 message 组件显示错误信息
- message.error(`游戏 ${index + 1} 配置不完整,缺少以下字段:${missingFieldNames.join('、').replaceAll('、', '、\n')}`)
- return
- }
- // 验证通过,创建 items 数组(如果不存在)
- if (!cardJson.value.game_list[index].items) {
- cardJson.value.game_list[index].items = []
- }
- currentGameIndex.value = index
- currentLevel.value = 1
- }
- const changedSteps = (steps: any) => {
- console.log('changedSteps:', cardJson.value.game_list[currentGameIndex.value].items)
- }
- const createSubItem = () => {
- // 重置表单并打开弹窗
- subItemForm.sub_subject.music_name = ''
- subItemForm.sub_subject.mb = ''
- subItemForm.sub_subject.ok = ''
- subItemForm.sub_subject.ob = ''
- subItemForm.sub_subject.err = ''
- subItemForm.sub_subject.eb = ''
- subItemForm.ok_key = []
- subItemForm.err_key = []
- subItemForm.ok_key_voice = {}
- subItemForm.err_key_voice = {}
- subItemModalVisible.value = true
- }
- // 新建二级文件夹
- const handleSaveSubItem = () => {
- // 基础校验:必须选择子主题音乐
- if (!subItemForm.sub_subject.music_name) {
- message.warning('请选择子主题音乐')
- return
- }
- const index = currentGameIndex.value
- const currentGame = cardJson.value.game_list[index]
- if (!currentGame) {
- message.error('未选择有效的游戏')
- return
- }
- // 确保 items 数组存在
- if (!currentGame.items) {
- currentGame.items = []
- }
- // 构造 items 下的新对象(遵循 API.CardJson21[game_list].items 的结构)
- const newItem = {
- sub_subject: {
- music_name: subItemForm.sub_subject.music_name,
- mb: 1,
- ok: '',
- ob: 1,
- err: '',
- eb: 1
- },
- ok_key: [],
- err_key: [],
- ok_key_voice: {},
- err_key_voice: {}
- }
- // 追加到 items
- currentGame.items.push(newItem)
- // 关闭弹窗并重置关键字段,便于下次新增
- subItemModalVisible.value = false
- subItemForm.sub_subject.music_name = ''
- }
- // 进入卡片配置
- const enterCardConfig = (index: number) => {
- currentSubFolderIndex.value = index
- const currentItem = cardJson.value.game_list[currentGameIndex.value]?.items?.[index]
- if (currentItem) {
- if (!currentItem.steps) {
- currentItem.steps = []
- }
- }
- currentLevel.value = 2
- }
- // 返回上级文件夹
- const goBack = () => {
- if (currentLevel.value > 0) {
- currentLevel.value--
- }
- }
- // 处理编辑游戏
- const handleEdit = (index: number) => {
- editingIndex.value = index
- // 将当前游戏数据复制到编辑表单
- Object.assign(editForm, JSON.parse(JSON.stringify(cardJson.value.game_list[index])))
- editModalVisible.value = true
- }
- // 处理删除游戏
- const handleDelete = (index: number) => {
- // 从游戏列表中删除指定索引的游戏
- cardJson.value.game_list.splice(index, 1)
- }
- // 处理编辑子项目
- const handleEditSubItem = (index: number) => {
- editingSubItemIndex.value = index
- // 将当前子项目数据复制到编辑表单
- const currentItem = cardJson.value.game_list[currentGameIndex.value].items[index]
- editSubItemForm.sub_subject.music_name = currentItem.sub_subject.music_name
- editSubItemForm.sub_subject.mb = currentItem.sub_subject.mb
- editSubItemForm.sub_subject.ok = currentItem.sub_subject.ok
- editSubItemForm.sub_subject.ob = currentItem.sub_subject.ob
- editSubItemForm.sub_subject.err = currentItem.sub_subject.err
- editSubItemForm.sub_subject.eb = currentItem.sub_subject.eb
- editSubItemModalVisible.value = true
- }
- // 处理删除子项目
- const handleDeleteSubItem = (index: number) => {
- // 从子项目列表中删除指定索引的项目
- cardJson.value.game_list[currentGameIndex.value].items.splice(index, 1)
- }
- // 保存子项目编辑
- const handleSaveSubItemEdit = () => {
- if (editingSubItemIndex.value >= 0) {
- // 基础校验:必须选择子主题音乐
- if (!editSubItemForm.sub_subject.music_name) {
- message.warning('请选择子主题音乐')
- return
- }
- // 将编辑表单的数据保存到子项目列表
- const currentItem = cardJson.value.game_list[currentGameIndex.value].items[editingSubItemIndex.value]
- currentItem.sub_subject.music_name = editSubItemForm.sub_subject.music_name
- currentItem.sub_subject.mb = editSubItemForm.sub_subject.mb || 1
- currentItem.sub_subject.ok = editSubItemForm.sub_subject.ok || ''
- currentItem.sub_subject.ob = editSubItemForm.sub_subject.ob || 1
- currentItem.sub_subject.err = editSubItemForm.sub_subject.err || ''
- currentItem.sub_subject.eb = editSubItemForm.sub_subject.eb || 1
- }
- editSubItemModalVisible.value = false
- editingSubItemIndex.value = -1
- }
- // 取消子项目编辑
- const handleCancelSubItemEdit = () => {
- editSubItemModalVisible.value = false
- editingSubItemIndex.value = -1
- }
- // 保存编辑
- const handleSaveEdit = () => {
- if (editingIndex.value >= 0) {
- // 将编辑表单的数据保存到游戏列表
- Object.assign(cardJson.value.game_list[editingIndex.value], JSON.parse(JSON.stringify(editForm)))
- }
- editModalVisible.value = false
- editingIndex.value = -1
- }
- // 取消编辑
- const handleCancelEdit = () => {
- editModalVisible.value = false
- editingIndex.value = -1
- }
- // 保存游戏配置
- const saveGameConfig = async () => {
- console.log('保存游戏配置:', CardController.stepsToItems(cardJson.value))
- const defaultJson = await CardController.getDefaultJson()
- CardController.add({
- header: {
- card_type: 21,
- ...cardJson.value.header
- },
- game_list: CardController.stepsToItems(cardJson.value).game_list
- })
- // 在这里可以添加保存逻辑,比如调用API保存cardJson
- // emit('update:open', false)
- }
- </script>
- <style lang='less' scoped>
- .create-folder-form {
- padding: 16px;
- background-color: #fff;
- border: 1px solid #d9d9d9;
- border-radius: 4px;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- }
- .config-game-page {
- width: 100%;
- height: 100%;
- }
- .back-button-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16px;
- }
- .game-modal-content {
- padding: 16px;
- .config-game-list {
- width: 100%;
- display: flex;
- flex-wrap: wrap;
- justify-content: flex-start;
- gap: 16px;
- height: 100%;
- }
- .config-game-item {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- align-items: center;
- cursor: pointer;
- border-radius: 8px;
- // transition: all 0.3s;
- background-color: #f5f5f5;
- padding: 0px !important;
- border: 1px solid #e9ecf1;
- box-sizing: border-box !important;
- margin-right: 16px;
- margin-bottom: 16px;
- position: relative;
- overflow: hidden;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
- .status-icon {
- position: absolute;
- top: 8px;
- left: 8px;
- z-index: 10;
- font-size: 16px;
- .status-complete {
- color: #52c41a;
- }
- .status-incomplete {
- color: #ff4d4f;
- }
- }
- .folder-icon {
- width: 86px;
- height: 86px;
- }
- .folder-footer {
- width: 100%;
- height: 32px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- border-top: 1px solid #e9ecf1;
- background-color: #fff;
- box-sizing: border-box;
- padding: 0 12px;
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- .action-icon {
- cursor: pointer;
- opacity: 0;
- transition: opacity 0.3s;
- font-size: 16px;
- color: #8c8c8c;
- &:hover {
- color: #1890ff;
- }
- }
- }
- .folder-info {
- width: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- padding: 12px 0;
- margin-bottom: 32px;
- .folder-title {
- font-weight: 500;
- margin-bottom: 8px;
- font-size: 14px;
- color: #333;
- }
- .music-badge {
- display: flex;
- align-items: center;
- gap: 4px;
- background-color: #e6f7ff;
- border-radius: 12px;
- padding: 3px 10px;
- font-size: 12px;
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
- .anticon {
- color: #1890ff;
- font-size: 12px;
- }
- .music-name {
- color: #1890ff;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: 80px;
- }
- }
- }
- &:hover {
- scale: 1.02;
- .folder-footer .action-icon {
- opacity: 1;
- }
- }
- &:hover {
- scale: 1.02;
- }
- }
- }
- .card-config-content {
- padding: 16px;
- h3 {
- margin-bottom: 24px;
- text-align: center;
- }
- }
- .step-list {
- display: flex;
- flex-direction: column;
- gap: 12px;
- }
- .step-item {
- display: flex;
- align-items: center;
- padding: 12px;
- border: 1px solid #d9d9d9;
- border-radius: 4px;
- cursor: grab;
- background-color: #fff;
- transition: all 0.3s;
- &:hover {
- border-color: #40a9ff;
- }
- }
- .step-item-active {
- border-color: #1890ff;
- box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
- }
- .step-number {
- font-weight: 500;
- margin-right: 16px;
- }
- .step-circles {
- display: flex;
- gap: 8px;
- flex-grow: 1;
- }
- .circle {
- width: 20px;
- height: 20px;
- border-radius: 50%;
- background-color: #f0f0f0;
- border: 1px solid #ccc;
- }
- .step-actions {
- cursor: pointer;
- }
- .selected-music-display {
- margin-top: 12px;
- padding: 10px 12px;
- background-color: #f6f8fa;
- border-radius: 6px;
- border: 1px solid #e1e4e8;
- transition: all 0.3s;
- }
- .music-info {
- display: flex;
- align-items: center;
- gap: 8px;
- .anticon {
- color: #1890ff;
- font-size: 16px;
- }
- .music-name {
- color: #333;
- font-size: 14px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- max-width: 300px;
- }
- }
- </style>
|