Selaa lähdekoodia

perf(views): 优化 UseGuidance 组件以及配置协议模块的界面

wangcong 3 kuukautta sitten
vanhempi
sitoutus
01414942d4

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

@@ -180,6 +180,7 @@
     "canNotFindProtocolType": "没有找到我的协议类型",
     "clickToDownloadTemplate": "点击下载模板",
     "clickToUpload": "填写必填项后,点击下方区域上传",
+    "configMethod": "配置方式",
     "confirmDeleteParams": "确定要删除这些协议参数吗?",
     "confirmResult": "确认结果",
     "createProtocol": "创建协议",

+ 94 - 34
src/layout/UseGuidance.vue

@@ -2,6 +2,7 @@
 import { computed, ref, useTemplateRef } from 'vue';
 import { useRouter } from 'vue-router';
 
+import SvgIcon from '@/components/SvgIcon.vue';
 import { t } from '@/i18n';
 import { addUnit } from '@/utils';
 
@@ -15,6 +16,7 @@ interface Props {
   form: T;
   rules: FormRules<T>;
   contentOffset?: number;
+  headerMargin?: number;
 }
 
 const props = defineProps<Props>();
@@ -22,6 +24,10 @@ const props = defineProps<Props>();
 const router = useRouter();
 const current = ref(0);
 
+const currentStep = computed(() => {
+  return props.steps[current.value];
+});
+
 const isFirstStep = computed(() => {
   return current.value === 0;
 });
@@ -55,10 +61,20 @@ const currentComponent = computed(() => {
 });
 
 const contentStyle = computed<CSSProperties>(() => {
-  const contentOffset = props.steps[current.value].contentOffset ?? props.contentOffset;
+  // const contentOffset = props.steps[current.value].contentOffset ?? props.contentOffset;
+
+  return {
+    // paddingLeft: addUnit(contentOffset ?? 312),
+  };
+});
+
+const headerStyle = computed<CSSProperties>(() => {
+  const dividerWidth = currentStep.value.hideHeaderDivider ? 0 : 1;
+  const headerMargin = currentStep.value.headerMargin ?? props.headerMargin;
 
   return {
-    paddingLeft: addUnit(contentOffset ?? 312),
+    borderBottomWidth: addUnit(dividerWidth),
+    marginBottom: addUnit(headerMargin ?? 40),
   };
 });
 
@@ -109,13 +125,17 @@ const finishCurrentStep = async () => {
       <div class="use-guide-steps">
         <ASteps v-model:current="current" :items="steps" direction="vertical" />
       </div>
-      <AButton class="use-guide-doc-button">
-        <img src="@/assets/img/file-black.png" />
+      <AButton class="icon-button doc-button">
+        <SvgIcon name="eye-o" />
         {{ $t('common.viewDoc') }}
       </AButton>
     </ALayoutSider>
     <ALayout>
       <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>
         <AForm ref="formRef" :model="form" :rules="rules" :layout="formLayout">
           <component
             ref="stepItem"
@@ -128,20 +148,26 @@ const finishCurrentStep = async () => {
         </AForm>
       </ALayoutContent>
       <ALayoutFooter class="use-guide-footer">
-        <div>
-          <AButton type="text" :disabled="isLastStep" @click="goNextStep">{{ $t('common.skip') }}</AButton>
-          <AButton type="text" @click="goPrevStep">{{ $t('common.return') }}</AButton>
-        </div>
-        <div>
-          <AButton v-if="exportButtonShow" @click="exportStepContent">{{ $t('common.exportToLocal') }}</AButton>
-          <AButton
-            v-show="nextStepButtonShow"
-            type="primary"
-            :disabled="nextStepButtonDisabled"
-            @click="finishCurrentStep"
-          >
-            {{ nextStepButtonText }}
-          </AButton>
+        <div class="use-guide-step-button-container">
+          <div>
+            <AButton type="text" :disabled="isLastStep" @click="goNextStep">{{ $t('common.skip') }}</AButton>
+            <AButton type="text" @click="goPrevStep">{{ $t('common.return') }}</AButton>
+          </div>
+          <div>
+            <AButton v-if="exportButtonShow" class="icon-button export-button" @click="exportStepContent">
+              <SvgIcon name="download" />
+              {{ $t('common.exportToLocal') }}
+            </AButton>
+            <AButton
+              v-show="nextStepButtonShow"
+              class="next-step-button"
+              type="primary"
+              :disabled="nextStepButtonDisabled"
+              @click="finishCurrentStep"
+            >
+              {{ nextStepButtonText }}
+            </AButton>
+          </div>
         </div>
       </ALayoutFooter>
     </ALayout>
@@ -154,8 +180,8 @@ const finishCurrentStep = async () => {
 }
 
 .use-guide-sider {
-  padding-top: 46px;
-  padding-bottom: 34px;
+  padding-top: 48px;
+  padding-bottom: 40px;
   background: #f0f0f0;
 
   :deep(.ant-layout-sider-children) {
@@ -165,7 +191,7 @@ const finishCurrentStep = async () => {
   }
 
   .use-guide-title {
-    margin-bottom: 26px;
+    margin-bottom: 32px;
     text-align: center;
   }
 
@@ -214,31 +240,65 @@ const finishCurrentStep = async () => {
     }
   }
 
-  .use-guide-doc-button {
-    display: flex;
-    align-items: center;
-
-    img {
-      margin-right: 10px;
-    }
+  .doc-button {
+    width: 120px;
+    height: 40px;
   }
 }
 
 .use-guide-main {
-  padding-top: 60px;
+  padding: 40px;
+  padding-bottom: 0;
   overflow: auto;
   background: var(--antd-color-bg-base);
+
+  .step-header {
+    padding-bottom: 40px;
+    border-bottom: 1px solid #e4e7ed;
+  }
+
+  .step-title {
+    margin-bottom: 8px;
+    font-size: 20px;
+    font-weight: 500;
+    line-height: 28px;
+    color: var(--antd-color-text);
+  }
+
+  .step-description {
+    min-height: 22px;
+    font-size: 14px;
+    line-height: 22px;
+    color: var(--antd-color-text-secondary);
+  }
 }
 
 .use-guide-footer {
+  padding-inline: 40px;
+  background: var(--antd-color-bg-base);
+}
+
+.use-guide-step-button-container {
   display: flex;
   justify-content: space-between;
-  padding-right: 211px;
-  padding-left: 187px;
-  background: var(--antd-color-bg-base);
+  max-width: 686px;
+
+  button {
+    height: 40px;
+  }
+
+  .ant-btn-text {
+    width: 80px;
+  }
+
+  .export-button {
+    width: 136px;
+    margin-right: 16px;
+  }
 
-  button + button {
-    margin-left: 16px;
+  .next-step-button {
+    width: 128px;
+    font-size: 16px;
   }
 }
 </style>

+ 10 - 0
src/styles/global.scss

@@ -57,3 +57,13 @@
   text-overflow: ellipsis;
   white-space: nowrap;
 }
+
+.icon-button {
+  display: inline-flex;
+  align-items: center;
+  font-size: 16px;
+
+  span {
+    margin-left: 8px;
+  }
+}

+ 5 - 0
src/types/index.ts

@@ -74,6 +74,11 @@ export interface DictValue {
 
 export interface UseGuideStepItem extends StepProps {
   title: string;
+  stepTitle?: string;
+  stepDescription?: string;
+  hideHeader?: boolean;
+  hideHeaderDivider?: boolean;
+  headerMargin?: number;
   component: Component;
   contentOffset?: number;
   formLayout?: 'horizontal' | 'vertical' | 'inline';

+ 13 - 10
src/views/setup-protocol/SelectConfigMethod.vue

@@ -34,19 +34,21 @@ const finish = () => {
       },
       {
         title: t('setupProtocol.waitingForRecognition'),
+        stepTitle: t('setupProtocol.recognizing'),
         component: shallowRef(WaitingRecognition),
         nextStepButtonHide: true,
       },
       {
         title: t('setupProtocol.confirmResult'),
+        stepTitle: t('setupProtocol.recognitionResult'),
         component: shallowRef(RecognitionResult),
-        contentOffset: 36,
         formLayout: 'vertical',
         exportButtonShow: true,
         nextStepButtonText: t('common.finishSetup'),
       },
       {
         title: t('common.finishSetup'),
+        hideHeader: true,
         component: shallowRef(FinishProtocol),
         isLastStep: true,
       },
@@ -60,7 +62,6 @@ const finish = () => {
       {
         title: t('setupProtocol.createProtocol'),
         component: shallowRef(CreateProtocol),
-        contentOffset: 36,
         formLayout: 'vertical',
         exportButtonShow: true,
         nextStepButtonText: t('common.finishSetup'),
@@ -80,17 +81,19 @@ defineExpose<UseGuideStepItemExpose>({
 
 <template>
   <div>
-    <div class="use-guide-title">{{ $t('setupProtocol.selectConfigMethod') }}</div>
-    <div class="use-guide-description config-description">{{ $t('setupProtocol.selectConfigMethodTip') }}</div>
-    <ARadioGroup v-model:value="form.configMethod">
-      <ARadio :value="ProtocolConfigMethod.ImportFromTemplate">{{ $t('setupProtocol.importFromTemplate') }}</ARadio>
-      <ARadio :value="ProtocolConfigMethod.ManuallyCreate">{{ $t('setupProtocol.manuallyCreate') }}</ARadio>
-    </ARadioGroup>
+    <AFormItem :label="$t('setupProtocol.configMethod')" name="configMethod">
+      <ARadioGroup class="config-radio-group" v-model:value="form.configMethod">
+        <ARadio :value="ProtocolConfigMethod.ImportFromTemplate">{{ $t('setupProtocol.importFromTemplate') }}</ARadio>
+        <ARadio :value="ProtocolConfigMethod.ManuallyCreate">{{ $t('setupProtocol.manuallyCreate') }}</ARadio>
+      </ARadioGroup>
+    </AFormItem>
   </div>
 </template>
 
 <style lang="scss" scoped>
-.config-description {
-  margin-bottom: 58px;
+.config-radio-group {
+  label {
+    margin-right: 110px;
+  }
 }
 </style>

+ 0 - 2
src/views/setup-protocol/SelectProtocolType.vue

@@ -34,8 +34,6 @@ defineExpose<UseGuideStepItemExpose>({
 
 <template>
   <div>
-    <div class="use-guide-title">{{ $t('setupProtocol.selectProtocolType') }}</div>
-    <div class="use-guide-description">{{ $t('setupProtocol.selectProtocolTypeTip') }}</div>
     <AFormItem :label="$t('setupProtocol.protocolType')" name="protocolType">
       <ASelect v-model:value="form.protocolType" class="protocol-select" :placeholder="$t('common.plzSelect')">
         <ASelectOption v-for="item in protocolTypes" :key="item.dictValueId" :value="item.dictValue">

+ 10 - 0
src/views/setup-protocol/SetupProtocol.vue

@@ -14,11 +14,14 @@ import type { FormRules, RuleValidator, SetupProtocolForm, UseGuideStepItem } fr
 const steps = ref<UseGuideStepItem[]>([
   {
     title: t('setupProtocol.selectProtocolType'),
+    stepDescription: t('setupProtocol.selectProtocolTypeTip'),
     component: shallowRef(SelectProtocolType),
   },
   {
     title: t('setupProtocol.selectConfigMethod'),
+    stepDescription: t('setupProtocol.selectConfigMethodTip'),
     component: shallowRef(SelectConfigMethod),
+    formLayout: 'vertical',
   },
 ]);
 
@@ -66,6 +69,13 @@ const rules = computed<FormRules<SetupProtocolForm>>(() => {
         trigger: 'change',
       },
     ],
+    configMethod: [
+      {
+        required: true,
+        message: t('common.plzSelect', { name: t('setupProtocol.configMethod') }),
+        trigger: 'blur',
+      },
+    ],
     deviceType: [
       {
         required: true,

+ 0 - 5
src/views/setup-protocol/UploadProtocolFile.vue

@@ -51,7 +51,6 @@ const downloadTemplate = () => {
 
 <template>
   <div>
-    <div class="use-guide-title upload-title">{{ $t('setupProtocol.uploadFile') }}</div>
     <div class="upload-step-text">1. {{ $t('setupProtocol.clickToDownloadTemplate') }}</div>
     <AButton class="upload-template-button" type="primary" @click="downloadTemplate">
       <img src="@/assets/img/file-white.png" />
@@ -76,10 +75,6 @@ const downloadTemplate = () => {
 </template>
 
 <style lang="scss" scoped>
-.upload-title {
-  margin-bottom: 51px;
-}
-
 .upload-step-text {
   margin-bottom: 8px;
   font-size: 14px;

+ 0 - 1
src/views/setup-protocol/WaitingRecognition.vue

@@ -41,7 +41,6 @@ onMounted(async () => {
 
 <template>
   <div>
-    <div class="use-guide-title">{{ $t('setupProtocol.recognizing') }}</div>
     <div class="recognize-tip">{{ $t('setupProtocol.recognizeTip', { time: remainingSeconds }) }}</div>
     <AProgress class="recognize-progress" :percent="currentPercent" />
   </div>