FeedbackDialog.vue 6.88 KB
<template>
  <el-dialog
    :model-value="modelValue"
    @update:model-value="handleUpdateModelValue"
    @close="handleClose"
    width="420px"
    :show-close="true"
    class="feedback-dialog"
    style="border-radius: 16px; padding: 14px 0 0 0"
  >
    <div class="feedback-title">{{ $t("common.feedbackDialog.title") }}</div>
    <div class="feedback-dialog-content">
      <div class="feedback-text">
        <p>{{ $t("common.feedbackDialog.description") }}</p>
        <p>
          {{ $t("common.feedbackDialog.bonus")
          }}<span class="highlight-text">{{
            $t("common.feedbackDialog.bonusHighlight")
          }}</span
          >{{ $t("common.feedbackDialog.bonusSuffix") }}
        </p>
        <p class="help-text">{{ $t("common.feedbackDialog.helpText") }}</p>
      </div>
      <div class="qr-code-container">
        <img
          :src="'/customerQr.png'"
          :alt="$t('common.feedbackDialog.qrCodeAlt')"
          class="qr-code-image"
        />
        <p class="qr-code-hint">{{ $t("common.feedbackDialog.qrCodeHint") }}</p>
      </div>
      <div class="feedback-checkbox">
        <el-checkbox v-model="dontRemindFor30Days">
          {{ $t("common.feedbackDialog.dontRemindFor30Days") }}
        </el-checkbox>
      </div>
    </div>
    <template #footer>
      <div class="feedback-dialog-footer">
        <div class="skip-btn" @click="handleSkip">
          {{ $t("common.feedbackDialog.skip") }}
        </div>
        <div class="feedback-btn" @click="handleGoToFeedback">
          {{ $t("common.feedbackDialog.goToFeedback") }}
        </div>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref } from "vue";
import { ElMessage } from "element-plus";
import { useI18n } from "vue-i18n";

interface Props {
  modelValue: boolean;
}

const props = defineProps<Props>();
const emit = defineEmits<{
  "update:modelValue": [value: boolean];
  close: [dontRemindFor30Days: boolean];
  skip: [dontRemindFor30Days: boolean];
  goToFeedback: [dontRemindFor30Days: boolean];
}>();

const { t } = useI18n();
const dontRemindFor30Days = ref(false);
const isClosingByButton = ref(false); // 标记是否通过按钮关闭(skip/goToFeedback)

const handleUpdateModelValue = (value: boolean) => {
  emit("update:modelValue", value);
  // 当弹窗关闭时(value 变为 false),如果不是通过按钮关闭的,才触发 close 事件
  // 这样可以避免在点击 skip/goToFeedback 按钮时重复触发 close 事件
  if (!value && !isClosingByButton.value) {
    emit("close", dontRemindFor30Days.value);
  }
  // 重置标记
  if (!value) {
    isClosingByButton.value = false;
  }
};

const handleClose = () => {
  emit("close", dontRemindFor30Days.value);
};

const handleSkip = () => {
  isClosingByButton.value = true;
  emit("skip", dontRemindFor30Days.value);
  emit("update:modelValue", false);
};

const handleGoToFeedback = () => {
  isClosingByButton.value = true;
  emit("goToFeedback", dontRemindFor30Days.value);
  emit("update:modelValue", false);
  ElMessage.info(t("common.feedbackDialog.feedbackDeveloping"));
};
</script>

<style scoped lang="scss">
.feedback-dialog {
  :deep(.el-dialog) {
    border-radius: 16px;
  }

  :deep(.el-dialog__headerbtn) {
    position: absolute;
    right: 20px;
    top: 20px;
    z-index: 10;
  }

  :deep(.el-dialog__body) {
    padding: 0;
  }

  :deep(.el-dialog__header) {
    padding: 0;
    border: none;
    position: relative;
  }

  :deep(.el-dialog__footer) {
    padding: 0;
    border-top: 1px solid var(--color-border, #e0e0e0);
  }
}

.feedback-dialog-content {
  display: flex;
  flex-direction: column;
  padding: 20px 20px 0px;
}

.feedback-title {
  font-size: 18px;
  color: #333333;
  font-weight: 600;
  text-align: center;
  padding: 0 0 20px;
  margin: 0;
  border-bottom: 1px solid var(--color-border, #e0e0e0);
  position: relative;
}

.feedback-text {
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-size: 14px;
  line-height: 1.6;
  color: #666666;
  text-align: center;
  padding: 0 16px;

  p {
    margin: 0;
    text-align: center;
  }

  .highlight-text {
    color: #ff8c00;
    font-weight: 500;
    text-align: center;
  }

  .help-text {
    color: var(--color-text-secondary, #666);
    font-size: 13px;
    text-align: center;
  }
}

.qr-code-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  background: var(--color-bg, #f5f5f5);
  border-radius: 8px;
  margin-bottom: 16px;

  .qr-code-image {
    width: 180px;
    height: 180px;
    object-fit: contain;
    border-radius: 4px;
    background: #fff;
    padding: 8px;
  }

  .qr-code-hint {
    margin: 0;
    font-size: 12px;
    color: var(--color-text-secondary, #666);
    text-align: center;
  }
}

.feedback-checkbox {
  display: flex;
  align-items: center;
  justify-content: center;
  border-top: 1px solid var(--color-border, #e0e0e0);
  padding-top: 4px;

  :deep(.el-checkbox__label) {
    font-size: 12px;
    color: #666666;
  }
}

.feedback-dialog-footer {
  display: flex;
  gap: 12px;
  justify-content: center;
  padding: 0px 20px 20px 20px;

  .skip-btn,
  .feedback-btn {
    flex: 1;
    padding: 10px 24px;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 500;
    text-align: center;
    cursor: pointer;
    transition: all 0.3s ease;
    user-select: none;
  }

  .skip-btn {
    background: #f5f5f5;
    color: #666666;

    &:hover {
      background: #e8e8e8;
      border-color: #d0d0d0;
    }

    &:active {
      background: #e0e0e0;
    }
  }

  .feedback-btn {
    background: var(--primary-color);
    border: none;
    color: white;
    box-shadow: 0 2px 8px rgba(51, 153, 255, 0.3);

    &:hover {
      box-shadow: 0 4px 12px rgba(51, 153, 255, 0.4);
      transform: translateY(-1px);
    }

    &:active {
      transform: translateY(0);
      box-shadow: 0 2px 6px rgba(51, 153, 255, 0.3);
    }
  }
}

// 深色主题适配
:root.theme-dark {
  .feedback-dialog {
    :deep(.el-dialog__header) {
      border-bottom-color: var(--color-border, #333);
    }

    :deep(.el-dialog__title) {
      color: var(--color-text, #ccc);
    }

    :deep(.el-dialog__footer) {
      border-top-color: var(--color-border, #333);
    }
  }

  .feedback-text {
    color: var(--color-text, #ccc);

    .help-text {
      color: var(--color-text-secondary, #888);
    }
  }

  .qr-code-container {
    background: var(--color-bg, #1a1a1a);

    .qr-code-image {
      background: #2a2a2a;
    }

    .qr-code-hint {
      color: var(--color-text-secondary, #888);
    }
  }

  .feedback-checkbox {
    :deep(.el-checkbox__label) {
      color: var(--color-text, #ccc);
    }
  }

  .feedback-dialog-footer {
    .skip-btn {
      background: #2a2a2a;
      border-color: #444;
      color: var(--color-text, #ccc);

      &:hover {
        background: #333;
        border-color: #555;
      }

      &:active {
        background: #2a2a2a;
      }
    }

    .feedback-btn {
      color: white;
    }
  }
}
</style>