123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- <template>
- <nut-popup v-model:visible="show" position="bottom">
- <view class="selector-container">
- <view class="selector-header">
- <view class="selector-title">选择游戏题目</view>
- <nut-button size="small" @click="onClose">取消</nut-button>
- </view>
- <scroll-view
- scroll-y
- class="puzzle-scroll"
- :style="{ maxHeight: scrollHeight + 'px' }"
- >
- <view class="puzzle-list">
- <view
- v-for="puzzle in puzzleOptions"
- :key="puzzle.value"
- class="puzzle-option"
- :class="{ 'disabled': puzzle.disabled, 'selected': selectedPuzzleId === puzzle.value }"
- @click="!puzzle.disabled && onSelect(puzzle)"
- >
- <view class="option-content">
- <view class="option-title">{{ puzzle.text }}</view>
- <view v-if="puzzle.description" class="option-desc">{{ puzzle.description }}</view>
- </view>
- <IconFont v-if="selectedPuzzleId === puzzle.value" name="check" color="#3C92FB" size="16"></IconFont>
- </view>
- </view>
- </scroll-view>
- </view>
- </nut-popup>
- </template>
-
- <script lang="ts">
- import { defineComponent, computed, PropType } from 'vue'
- import { IconFont } from '@nutui/icons-vue-taro'
- import { CascaderOption } from '@/types/cascader'
-
- export default defineComponent({
- name: 'PuzzleSelector',
- components: {
- IconFont
- },
- props: {
- visible: {
- type: Boolean,
- default: false
- },
- puzzleOptions: {
- type: Array as PropType<CascaderOption[]>,
- default: () => []
- },
- selectedPuzzleId: {
- type: String,
- default: ''
- },
- scrollHeight: {
- type: Number,
- default: 300
- }
- },
- emits: ['update:visible', 'select-puzzle'],
- setup(props, { emit }) {
- const show = computed({
- get: () => props.visible,
- set: (val) => emit('update:visible', val)
- })
-
- const onClose = () => {
- show.value = false
- }
-
- const onSelect = (puzzle) => {
- emit('select-puzzle', puzzle)
- }
-
- return {
- show,
- onClose,
- onSelect
- }
- }
- })
- </script>
-
- <style lang="scss">
- .selector-container {
- padding: $spacing-base;
-
- .selector-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: $spacing-base 0;
- margin-bottom: $spacing-base;
- border-bottom: 1px solid $border-color-light;
-
- .selector-title {
- font-size: $font-size-medium;
- font-weight: $font-weight-medium;
- color: $text-color-primary;
- }
- }
-
- .puzzle-scroll {
- border: 1px solid $border-color-light;
- border-radius: $border-radius-small;
- margin-top: $spacing-base;
- background-color: $background-color-light;
- }
-
- .puzzle-list {
- padding: $spacing-small;
-
- .puzzle-option {
- background-color: $background-color-base;
- padding: $spacing-base;
- border-radius: $border-radius-mini;
- margin-bottom: $spacing-small;
- box-shadow: $shadow-light;
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- &:last-child {
- margin-bottom: 0;
- }
-
- &.disabled {
- opacity: 0.5;
- }
-
- &.selected {
- background-color: rgba(60, 146, 251, 0.1);
- }
-
- .option-content {
- flex: 1;
-
- .option-title {
- font-size: $font-size-base;
- color: $text-color-primary;
- margin-bottom: $spacing-mini;
- }
-
- .option-desc {
- font-size: $font-size-small;
- color: $text-color-secondary;
- }
- }
- }
- }
- }
- </style>
|