form-content.vue 3 KB
<script setup lang="ts">
import { useSelectionStore } from "@/store";

import {
  Layout,
  LayoutSider,
  LayoutContent,
  LayoutFooter,
  Step,
  Steps,
  Space,
  Divider,
  Link
} from "@arco-design/web-vue";
import Step1FormContent from "@/views/demo/components/step1-form-content.vue";
import Step2FormContent from "@/views/demo/components/step2-form-content.vue";
import Step3FormContent from "@/views/demo/components/step3-form-content.vue";
import IconButton from "@/components/icon-button/index.vue";

import { AnyObject } from "@/types/global";
import useLoading from "@/hooks/loading";
import { computed, markRaw, ref } from "vue";
import { cloneDeep } from "lodash";

const props = defineProps<{
  initValue: AnyObject;
  filterProject?: (value: unknown) => boolean;
  onSubmit: (data: AnyObject) => Promise<any>;
}>();

const { loading, setLoading } = useLoading(false);
const formRef = ref();
const formValue = ref({ ...cloneDeep(props.initValue) });

const stepItems = [
  { value: 1, label: "基本信息", template: markRaw(Step1FormContent) },
  { value: 2, label: "补充信息", template: markRaw(Step2FormContent) },
  { value: 3, label: "上传文件", template: markRaw(Step3FormContent) }
];

const currentStep = ref(1);
const currentContent = computed(() => stepItems.find((item) => item.value === currentStep.value)?.template);
const nextBtnLabel = computed(() => (currentStep.value === 3 ? "提交" : "下一步"));

const onPrev = (): void => {
  currentStep.value = Math.max(1, currentStep.value - 1);
};

const onNext = () => {
  formRef.value.onValid(async () => {
    if (currentStep.value === stepItems.length) {
      setLoading(true);
      props.onSubmit(formValue.value).finally(() => setLoading(false));
    }
    currentStep.value = Math.min(stepItems.length, currentStep.value + 1);
  });
};
</script>

<template>
  <Layout>
    <Layout has-sider>
      <LayoutSider :width="120" class="aside">
        <Steps :current="currentStep" direction="vertical" :small="true">
          <Step v-for="item in stepItems" :key="item.value">{{ item.label }}</Step>
        </Steps>
      </LayoutSider>
      <LayoutContent class="main">
        <component :is="currentContent" ref="formRef" v-model="formValue" v-model:loading="loading"
                   :filter-project="filterProject" />
      </LayoutContent>
    </Layout>
    <LayoutFooter>
      <Divider style="margin-top: 8px; margin-bottom: 20px" />
      <Link :href="useSelectionStore().lyricTool" :hoverable="false" class="link-hover" icon>歌词制作工具</Link>
      <Space style="float: right">
        <IconButton v-show="currentStep !== 1" icon="left" label="上一步" @click="onPrev" />
        <IconButton icon="right" icon-align="right" :loading="loading" :label="nextBtnLabel" @click="onNext" />
      </Space>
    </LayoutFooter>
  </Layout>
</template>

<style scoped lang="less">
.aside {
  box-shadow: unset !important;
  border-right: 1px solid var(--color-border);
  margin-right: 20px;
  background-color: transparent;
}

.main {
  min-width: 640px;
}
</style>