|
@@ -1,39 +1,231 @@
|
|
|
<template>
|
|
|
- <a-steps changeable :current="current" @change="setCurrent">
|
|
|
- <a-step description="This is a description">Succeeded</a-step>
|
|
|
- <a-step description="This is a description">Processing</a-step>
|
|
|
- <a-step description="This is a description">Pending</a-step>
|
|
|
- </a-steps>
|
|
|
- <div :style="{
|
|
|
- width: '100%',
|
|
|
- height: '200px',
|
|
|
- textAlign: 'center',
|
|
|
- background: 'var(--color-bg-2)',
|
|
|
- color: '#C2C7CC',
|
|
|
- }">
|
|
|
- <a-space size="large">
|
|
|
- <a-button type="secondary" :disabled="current <= 1" @click="onPrev">
|
|
|
- <IconLeft /> Back
|
|
|
+ <div>
|
|
|
+ <div class="header">
|
|
|
+ <a-button type="primary" @click="onCancel">
|
|
|
+ 返回
|
|
|
</a-button>
|
|
|
- <a-button type="primary" :disabled="current >= 3" @click="onNext">
|
|
|
- Next
|
|
|
- <IconRight />
|
|
|
- </a-button>
|
|
|
- </a-space>
|
|
|
+ </div>
|
|
|
+ <a-steps changeable :current="current" @change="setCurrent" label-placement="vertical">
|
|
|
+ <!-- 数组格式 -->
|
|
|
+ <template v-if="isShowArray">
|
|
|
+ <a-step v-for="(step, index) in StepsData" :key="index">
|
|
|
+ 第{{ index + 1 }}步
|
|
|
+ <template #icon v-if="submitShow && current == (maxStep)">
|
|
|
+ <icon-loading />
|
|
|
+ </template>
|
|
|
+ </a-step>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <a-step>结果</a-step>
|
|
|
+ </a-steps>
|
|
|
+
|
|
|
+ <!-- 动态渲染表单数据 -->
|
|
|
+ <template v-if="isShowArray">
|
|
|
+ <keep-alive>
|
|
|
+ <div class="steps-conter">
|
|
|
+ <div>
|
|
|
+ <div v-for="(item, index) in StepsData[current - 1]" :key="item.id || item.field">
|
|
|
+ <div :style="{ width: width }" v-show="visibleShowMap[item.field]">
|
|
|
+ <a-form-item :label="item.label" :rules="item.rules" :field="item.field"
|
|
|
+ :validate-trigger="rulesTagse(item?.rules)">
|
|
|
+ <!-- 使用 key 触发重新渲染 -->
|
|
|
+ <component :is="'a-' + item.type" v-model="formState[item.field]"
|
|
|
+ :placeholder="item.type === 'input' ? '请输入' : '请选择' + item.label" allow-clear
|
|
|
+ :style="{ width: item.width ? item.width + 'px' : '' }"
|
|
|
+ :key="formState[item.field]">
|
|
|
+ <template v-if="item.type === 'select'">
|
|
|
+ <a-option v-for="option in item.options" :key="option.value"
|
|
|
+ :value="option.value">
|
|
|
+ {{ option.label }}
|
|
|
+ </a-option>
|
|
|
+ </template>
|
|
|
+ </component>
|
|
|
+ </a-form-item>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </keep-alive>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 如果 StepsData 不是数组的格式,渲染单个表单项 -->
|
|
|
+ <template v-if="!isShowArray">
|
|
|
+ <component :is="'a-' + StepsData.type" v-model="StepsData.value"
|
|
|
+ :placeholder="StepsData.type === 'input' ? '请输入' : '请选择' + StepsData.label" allow-clear
|
|
|
+ :style="{ width: StepsData.width ? StepsData.width + 'px' : '' }">
|
|
|
+ <template v-if="StepsData.type === 'select'">
|
|
|
+ <a-option v-for="option in StepsData.options" :key="option.value" :value="option.value">
|
|
|
+ {{ option.label }}
|
|
|
+ </a-option>
|
|
|
+ </template>
|
|
|
+ </component>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 底部按钮 -->
|
|
|
+ <div class="step-footer">
|
|
|
+ <a-space size="large">
|
|
|
+ <template v-if="isShowArray">
|
|
|
+ <a-button type="secondary" :disabled="current <= 1" @click="onPrev">
|
|
|
+ <IconLeft /> 上一步
|
|
|
+ </a-button>
|
|
|
+ <a-button type="primary" :disabled="current >= maxStep" @click="onNext" v-if="maxStep !== current">
|
|
|
+ 下一步
|
|
|
+ <IconRight />
|
|
|
+ </a-button>
|
|
|
+
|
|
|
+ <a-button type="primary" @click="onFinish" v-else>
|
|
|
+ 确认
|
|
|
+ </a-button>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="!isShowArray">
|
|
|
+ <a-button type="primary" @click="onCancel">
|
|
|
+ 取消
|
|
|
+ </a-button>
|
|
|
+ <a-button type="primary" @click="onFinish">
|
|
|
+ 确认
|
|
|
+ </a-button>
|
|
|
+ </template>
|
|
|
+ </a-space>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
+
|
|
|
<script setup>
|
|
|
-import { reactive } from 'vue'
|
|
|
- const current = reactive(1)
|
|
|
- onPrev() {
|
|
|
- current = Math.max(1, this.current - 1)
|
|
|
- }
|
|
|
-
|
|
|
- onNext() {
|
|
|
- current = Math.min(3, this.current + 1)
|
|
|
- }
|
|
|
-
|
|
|
- setCurrent(current) {
|
|
|
- current = current
|
|
|
- }
|
|
|
-</script>
|
|
|
+import { ref, defineProps, toRefs, computed, defineEmits } from 'vue';
|
|
|
+
|
|
|
+// const StepsData = [
|
|
|
+// [
|
|
|
+// { type: 'select', label: '姓名', field: 'name', value: '',options:[], isVisible: (item, e) => {
|
|
|
+// if(e.gender=='male'){
|
|
|
+// item.options = [{ value: 'male', label: '男' }, { value: 'female', label: '女' }]
|
|
|
+// }
|
|
|
+// return e.gender=='male'
|
|
|
+// } },
|
|
|
+// { type: 'select', label: '性别', field: 'gender',value:"", options: [{ value: 'male', label: '男' }, { value: 'female', label: '女' }] },
|
|
|
+// ],
|
|
|
+// [
|
|
|
+// { type: 'input', label: '年龄', field: 'age', value: '' },
|
|
|
+// { type: 'input', label: '电话', field: 'phone', value: '' },
|
|
|
+// ],
|
|
|
+]
|
|
|
+const props = defineProps({
|
|
|
+ StepsData: {
|
|
|
+ type: Array,
|
|
|
+ default: () => [] // 默认值设置为数组套数组
|
|
|
+ }, // 步骤条数据层
|
|
|
+ width: {
|
|
|
+ type: [String, Number],
|
|
|
+ default: "50vw"
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+const emit = defineEmits(['step-change', 'onCancel', 'onSubmit']);
|
|
|
+
|
|
|
+const { StepsData, width } = toRefs(props);
|
|
|
+
|
|
|
+// 判断当前是否是数组套数组
|
|
|
+const isShowArray = computed(() => Array.isArray(StepsData.value));
|
|
|
+
|
|
|
+// 初始化表单状态
|
|
|
+const formState = ref({});
|
|
|
+const current = ref(1);
|
|
|
+const submitShow = ref(false)
|
|
|
+// 计算最大步骤数
|
|
|
+const maxStep = computed(() => (isShowArray.value ? StepsData.value.length : 1));
|
|
|
+
|
|
|
+// 初始化 formState
|
|
|
+if (isShowArray.value) {
|
|
|
+ StepsData.value.forEach(step => {
|
|
|
+ step.forEach(item => {
|
|
|
+ if (item.field) {
|
|
|
+ formState.value[item.field] = item.value;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+} else if (StepsData.value && StepsData.value.value) {
|
|
|
+ formState.value = StepsData.value.value;
|
|
|
+}
|
|
|
+
|
|
|
+// 使用 computed 来动态计算每个表单项的可见性
|
|
|
+const visibleShowMap = computed(() => {
|
|
|
+ const visibilityMap = {};
|
|
|
+ // 遍历每个步骤,计算每个表单项的可见性
|
|
|
+ StepsData.value.forEach((step) => {
|
|
|
+ step.forEach((item) => {
|
|
|
+ if (item.field) {
|
|
|
+ if (item.isVisible) {
|
|
|
+ if (typeof item.isVisible === 'function') {
|
|
|
+ // 如果 isVisible 是函数,执行并设置结果
|
|
|
+ visibilityMap[item.field] = item.isVisible(item, formState.value);
|
|
|
+ } else {
|
|
|
+ // 否则直接使用 isVisible 的值
|
|
|
+ visibilityMap[item.field] = item.isVisible;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ visibilityMap[item.field] = true; // 默认可见
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ return visibilityMap;
|
|
|
+});
|
|
|
+
|
|
|
+// 表单验证方式
|
|
|
+const rulesTagse = (item) => {
|
|
|
+ if (!item) return ''
|
|
|
+ return item[0]?.trigger
|
|
|
+}
|
|
|
+
|
|
|
+// 上一步
|
|
|
+const onPrev = () => {
|
|
|
+ current.value = Math.max(1, current.value - 1);
|
|
|
+};
|
|
|
+
|
|
|
+// 下一步
|
|
|
+const onNext = () => {
|
|
|
+ current.value = Math.min(maxStep.value, current.value + 1);
|
|
|
+};
|
|
|
+
|
|
|
+// 点击步骤条
|
|
|
+const setCurrent = (e) => {
|
|
|
+ current.value = e;
|
|
|
+ emit('step-change', e); // Emit step change to parent
|
|
|
+};
|
|
|
+
|
|
|
+// 取消
|
|
|
+const onCancel = () => {
|
|
|
+ emit('onCancel', true)
|
|
|
+}
|
|
|
+
|
|
|
+// 确认
|
|
|
+const onFinish = () => {
|
|
|
+ emit('onSubmit', formState.value)
|
|
|
+ current.value = Math.min(maxStep.value+1, current.value + 1);
|
|
|
+ submitShow.value = true
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.step-footer {
|
|
|
+ width: 100%;
|
|
|
+ height: 200px;
|
|
|
+ text-align: center;
|
|
|
+ background: var(--color-bg-2);
|
|
|
+ color: #C2C7CC;
|
|
|
+ padding-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.steps-conter {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ margin-top: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.header {
|
|
|
+ margin-bottom: 50px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: end;
|
|
|
+}
|
|
|
+</style>
|