Преглед на файлове

feat(components): 编写 ModalGuidance 组件,并调整 UseGuidance 组件逻辑和样式以适配

wangcong преди 1 месец
родител
ревизия
2e694b09a0
променени са 4 файла, в които са добавени 150 реда и са изтрити 7 реда
  1. 7 0
      src/constants/inject-key.ts
  2. 2 0
      src/i18n/locales/zh.json
  3. 63 0
      src/layout/ModalGuidance.vue
  4. 78 7
      src/layout/UseGuidance.vue

+ 7 - 0
src/constants/inject-key.ts

@@ -0,0 +1,7 @@
+import type { InjectionKey } from 'vue';
+
+export const IS_USED_IN_MODAL_GUIDANCE: InjectionKey<boolean> = Symbol('isUsedInModalGuidance');
+
+export const CLOSE_MODAL_GUIDANCE: InjectionKey<() => void> = Symbol('closeModalGuidance');
+
+export const FINISH_MODAL_GUIDANCE: InjectionKey<() => void> = Symbol('finishModalGuidance');

+ 2 - 0
src/i18n/locales/zh.json

@@ -7,6 +7,7 @@
     "advancedSettings": "高级设置",
     "aiCtrl": "AI智控",
     "all": "所有",
+    "andCloseModal": "并关闭对话框?",
     "basicInfo": "基础信息",
     "batchSetting": "批量设置",
     "binding": "绑定",
@@ -45,6 +46,7 @@
     "pleaseEnter": "请输入",
     "plzEnter": "请输入{name}",
     "plzSelect": "请选择{name}",
+    "prevStep": "上一步",
     "query": "查询",
     "reLogin": "你已被登出,请重新登录",
     "recent1Day": "最近 1 天",

+ 63 - 0
src/layout/ModalGuidance.vue

@@ -0,0 +1,63 @@
+<script setup lang="ts" generic="T extends Record<string, any>">
+import { computed, provide } from 'vue';
+
+import { useViewVisible } from '@/hooks/view-visible';
+import { t } from '@/i18n';
+import { CLOSE_MODAL_GUIDANCE, FINISH_MODAL_GUIDANCE, IS_USED_IN_MODAL_GUIDANCE } from '@/constants/inject-key';
+
+interface Props {
+  title?: string;
+}
+
+const props = defineProps<Props>();
+
+const emit = defineEmits<{
+  finish: [];
+}>();
+
+const { visible, showView, hideView } = useViewVisible();
+
+const modalTitle = computed(() => {
+  return props.title ?? t('common.add');
+});
+
+const finish = () => {
+  emit('finish');
+};
+
+provide(IS_USED_IN_MODAL_GUIDANCE, true);
+provide(CLOSE_MODAL_GUIDANCE, hideView);
+provide(FINISH_MODAL_GUIDANCE, finish);
+
+defineExpose({
+  showView,
+  hideView,
+});
+</script>
+
+<template>
+  <AModal
+    v-model:open="visible"
+    wrap-class-name="modal-guidance-modal"
+    :title="modalTitle"
+    :width="1140"
+    centered
+    :footer="null"
+    :mask-closable="false"
+    destroy-on-close
+  >
+    <slot></slot>
+  </AModal>
+</template>
+
+<style lang="scss">
+.modal-guidance-modal {
+  .ant-modal-content {
+    height: 638px;
+  }
+
+  .ant-modal-body {
+    height: calc(100% - 40px);
+  }
+}
+</style>

+ 78 - 7
src/layout/UseGuidance.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts" generic="T extends Record<string, any>">
-import { computed, ref, useTemplateRef } from 'vue';
+import { computed, inject, ref, useTemplateRef } from 'vue';
 import { useRoute, useRouter } from 'vue-router';
 import { message } from 'ant-design-vue';
 
@@ -7,6 +7,7 @@ import ConfirmModal from '@/components/ConfirmModal.vue';
 import SvgIcon from '@/components/SvgIcon.vue';
 import { t } from '@/i18n';
 import { addUnit } from '@/utils';
+import { CLOSE_MODAL_GUIDANCE, FINISH_MODAL_GUIDANCE, IS_USED_IN_MODAL_GUIDANCE } from '@/constants/inject-key';
 
 import type { CSSProperties } from 'vue';
 import type { FormInstance } from 'ant-design-vue';
@@ -23,6 +24,9 @@ interface Props {
 
 const props = defineProps<Props>();
 
+const isUsedInModalGuidance = inject(IS_USED_IN_MODAL_GUIDANCE, false);
+const closeModalGuidance = inject(CLOSE_MODAL_GUIDANCE, undefined);
+const finishModalGuidance = inject(FINISH_MODAL_GUIDANCE, undefined);
 const route = useRoute();
 const router = useRouter();
 const current = ref(0);
@@ -46,10 +50,11 @@ const contentStyle = computed<CSSProperties>(() => {
 const headerStyle = computed<CSSProperties>(() => {
   const dividerWidth = currentStep.value.hideHeaderDivider ? 0 : 1;
   const headerMargin = currentStep.value.headerMargin ?? props.headerMargin;
+  const defaultMargin = isUsedInModalGuidance ? 24 : 40;
 
   return {
     borderBottomWidth: addUnit(dividerWidth),
-    marginBottom: addUnit(headerMargin ?? 40),
+    marginBottom: addUnit(headerMargin ?? defaultMargin),
   };
 });
 
@@ -75,6 +80,12 @@ const goPrevStep = async () => {
 };
 
 const goOutOfUseGuide = () => {
+  if (isUsedInModalGuidance) {
+    confirmModalRef.value?.hideView();
+    closeModalGuidance?.();
+    return;
+  }
+
   // 配置完成某一项时,路由查询参数 doneItems 会携带该项的页面路径,据此判断是否已经配置该项
   let doneItems = route.query.doneItems ?? '';
 
@@ -94,6 +105,11 @@ const goOutOfUseGuide = () => {
 
 const confirmModalRef = useTemplateRef('confirmModal');
 
+const confirmModalDescription = computed(() => {
+  const endText = isUsedInModalGuidance ? t('common.andCloseModal') : t('common.returnFirstUse');
+  return t('common.skipStepConfirm', { name: currentStep.value.title }) + endText;
+});
+
 const skipCurrentStep = () => {
   confirmModalRef.value?.showView();
 };
@@ -112,6 +128,7 @@ const finishCurrentStep = async () => {
 
     if (currentStep.value.isLastStep) {
       goOutOfUseGuide();
+      finishModalGuidance?.();
     } else {
       goNextStep();
     }
@@ -127,7 +144,7 @@ const finishCurrentStep = async () => {
 
 <template>
   <ALayout class="use-guide-container">
-    <ALayoutSider class="use-guide-sider" :width="268">
+    <ALayoutSider v-if="!isUsedInModalGuidance" class="use-guide-sider" :width="268">
       <div class="use-guide-title">{{ title }}</div>
       <div class="use-guide-steps">
         <ASteps :current="current" :items="steps" direction="vertical" />
@@ -141,7 +158,7 @@ const finishCurrentStep = async () => {
       <ALayoutContent class="use-guide-main" :style="contentStyle">
         <div v-show="!currentStep.hideHeader" class="step-header" :style="headerStyle">
           <div class="step-title">{{ currentStep.stepTitle || currentStep.title }}</div>
-          <div class="step-description">{{ currentStep.stepDescription }}</div>
+          <div v-if="!isUsedInModalGuidance" class="step-description">{{ currentStep.stepDescription }}</div>
         </div>
         <AForm
           ref="formRef"
@@ -166,10 +183,20 @@ const finishCurrentStep = async () => {
       <ALayoutFooter class="use-guide-footer">
         <div class="use-guide-step-button-container">
           <div>
-            <AButton type="text" :disabled="currentStep.isLastStep" @click="skipCurrentStep">
+            <AButton
+              :type="isUsedInModalGuidance ? 'default' : 'text'"
+              :disabled="currentStep.isLastStep"
+              @click="skipCurrentStep"
+            >
               {{ $t('common.skip') }}
             </AButton>
-            <AButton type="text" @click="goPrevStep">{{ $t('common.return') }}</AButton>
+            <AButton
+              v-show="!isUsedInModalGuidance || !isFirstStep"
+              :type="isUsedInModalGuidance ? 'default' : 'text'"
+              @click="goPrevStep"
+            >
+              {{ isUsedInModalGuidance ? $t('common.prevStep') : $t('common.return') }}
+            </AButton>
           </div>
           <div>
             <AButton v-if="currentStep.exportButtonShow" class="icon-button export-button" @click="exportStepContent">
@@ -189,7 +216,7 @@ const finishCurrentStep = async () => {
           <ConfirmModal
             ref="confirmModal"
             :title="$t('common.skipConfirm')"
-            :description-text="$t('common.skipStepConfirm', { name: currentStep.title }) + $t('common.returnFirstUse')"
+            :description-text="confirmModalDescription"
             :icon="{ name: 'exclamation' }"
             icon-bg-color="#F56C6C"
             @confirm="goOutOfUseGuide"
@@ -328,4 +355,48 @@ const finishCurrentStep = async () => {
     font-size: 16px;
   }
 }
+
+.modal-guidance-modal {
+  .use-guide-main {
+    padding: 0;
+    overflow-x: hidden;
+  }
+
+  .step-header {
+    padding-bottom: 0;
+    margin-top: 16px;
+    border: none;
+  }
+
+  .step-title {
+    padding-left: 8px;
+    margin-bottom: 0;
+    font-size: 16px;
+    font-weight: 600;
+    line-height: 24px;
+    color: #333;
+    border-left: 2px solid var(--antd-color-primary);
+  }
+
+  .use-guide-footer {
+    padding-inline: 0;
+    padding-bottom: 4px;
+  }
+
+  .use-guide-step-button-container {
+    justify-content: flex-end;
+
+    button {
+      min-width: 76px;
+      height: 32px;
+      margin-left: 16px;
+      font-size: 14px;
+    }
+
+    .next-step-button {
+      width: auto;
+      font-size: 14px;
+    }
+  }
+}
 </style>