Commit 07d508e19019df7925bdc04d47438a16bf0aac6c

Authored by 黄 x
1 parent 0923c9a5

fix(front): 设备添加采用分步完善

... ... @@ -7,26 +7,47 @@
7 7 width="500px"
8 8 @ok="handleSubmit"
9 9 >
10   - <BasicForm @register="registerForm"/>
  10 + <BasicForm @register="registerForm">
  11 + <template #iconSelect>
  12 + <Upload
  13 + name="avatar"
  14 + list-type="picture-card"
  15 + class="avatar-uploader"
  16 + :show-upload-list="false"
  17 + :customRequest="customUpload"
  18 + :before-upload="beforeUpload"
  19 + >
  20 + <img v-if="devicePic" :src="devicePic" alt="avatar"/>
  21 + <div v-else>
  22 + <loading-outlined v-if="loading"></loading-outlined>
  23 + <plus-outlined v-else></plus-outlined>
  24 + <div class="ant-upload-text">图片上传</div>
  25 + </div>
  26 + </Upload>
  27 + </template>
  28 + </BasicForm>
11 29 </BasicDrawer>
12 30 </template>
13 31 <script lang="ts">
14 32 import { defineComponent, ref, computed, unref } from 'vue';
15 33 import { BasicForm, useForm } from '/@/components/Form';
16   - import { formSchema } from './config.data';
  34 + import { formSchema } from './device.data';
17 35 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
18 36 import {saveOrEditMessageConfig} from "/@/api/message/config";
19 37 import {useMessage} from "/@/hooks/web/useMessage";
  38 + import {upload} from "/@/api/oss/ossFileUploader";
  39 + import {message, Upload} from "ant-design-vue";
  40 + import {FileItem} from "/@/components/Upload/src/typing";
20 41
21 42 export default defineComponent({
22   - name: 'ConfigDrawer',
23   - components: { BasicDrawer, BasicForm },
  43 + name: 'DeviceDrawer',
  44 + components: { BasicDrawer, BasicForm,Upload },
24 45 emits: ['success', 'register'],
25 46 setup(_, { emit }) {
26 47 const isUpdate = ref(true);
27   -
  48 + const devicePic = ref("");
28 49 const [registerForm, { validate,setFieldsValue,resetFields }] = useForm({
29   - labelWidth: 120,
  50 + labelWidth: 80,
30 51 schemas: formSchema,
31 52 showActionButtonGroup: false,
32 53 });
... ... @@ -46,7 +67,7 @@
46 67 }
47 68 });
48 69
49   - const getTitle = computed(() => (!unref(isUpdate) ? '新增消息配置' : '编辑消息配置'));
  70 + const getTitle = computed(() => (!unref(isUpdate) ? '新增设备' : '编辑设备'));
50 71
51 72 async function handleSubmit() {
52 73 try {
... ... @@ -78,13 +99,43 @@
78 99 setDrawerProps({ confirmLoading: false });
79 100 }
80 101 }
  102 + async function customUpload({file}) {
  103 + if (beforeUpload(file)) {
  104 + const formData = new FormData()
  105 + formData.append('file', file)
  106 + const response = await upload(formData);
  107 + if (response.fileStaticUri) {
  108 + devicePic.value = response.fileStaticUri;
  109 + }
  110 + }
  111 + }
81 112
  113 + const beforeUpload = (file: FileItem) => {
  114 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  115 + if (!isJpgOrPng) {
  116 + message.error('只能上传图片文件!');
  117 + }
  118 + const isLt2M = file.size as number / 1024 / 1024 < 2;
  119 + if (!isLt2M) {
  120 + message.error('图片大小不能超过2MB!');
  121 + }
  122 + return isJpgOrPng && isLt2M;
  123 + };
82 124 return {
83 125 registerDrawer,
84 126 registerForm,
85 127 getTitle,
86 128 handleSubmit,
  129 + beforeUpload,
  130 + customUpload,
  131 + devicePic
87 132 };
88 133 },
89 134 });
90 135 </script>
  136 +<style>
  137 +.ant-upload-select-picture-card i {
  138 + font-size: 32px;
  139 + color: #999;
  140 +}
  141 +</style>
... ...
  1 +<template>
  2 + <BasicModal
  3 + v-bind="$attrs"
  4 + width="55rem"
  5 + @register="register"
  6 + :title=getTitle
  7 + @visible-change="handleVisibleChange"
  8 + >
  9 + <div class="step-form-form">
  10 + <a-steps :current="current">
  11 + <a-step title="填写设备信息" />
  12 + <a-step title="确认转账信息" />
  13 + <a-step title="完成" />
  14 + </a-steps>
  15 + </div>
  16 + <div class="mt-5">
  17 + <DeviceStep1 @next="handleStep1Next" v-show="current === 0" />
  18 + <DeviceStep2
  19 + @prev="handleStepPrev"
  20 + @next="handleStep2Next"
  21 + v-show="current === 1"
  22 + v-if="initStep2"
  23 + />
  24 + <DeviceStep3 v-show="current === 2" @redo="handleRedo" v-if="initStep3" />
  25 + </div>
  26 + </BasicModal>
  27 +</template>
  28 +<script lang="ts">
  29 +import {defineComponent, ref, nextTick, computed, unref, reactive, toRefs} from 'vue';
  30 + import { BasicModal, useModalInner } from '/@/components/Modal';
  31 + import { BasicForm, FormSchema, useForm } from '/@/components/Form';
  32 + import DeviceStep1 from "/@/views/device/step/DeviceStep1.vue";
  33 + import DeviceStep2 from "/@/views/device/step/DeviceStep2.vue";
  34 + import DeviceStep3 from "/@/views/device/step/DeviceStep3.vue";
  35 + import { Steps } from "ant-design-vue";
  36 + const schemas: FormSchema[] = [
  37 + {
  38 + field: 'field1',
  39 + component: 'Input',
  40 + label: '字段1',
  41 + colProps: {
  42 + span: 24,
  43 + },
  44 + defaultValue: '111',
  45 + },
  46 + {
  47 + field: 'field2',
  48 + component: 'Input',
  49 + label: '字段2',
  50 + colProps: {
  51 + span: 24,
  52 + },
  53 + },
  54 + ];
  55 + export default defineComponent({
  56 + name:'DeviceModal',
  57 + components: { BasicModal, BasicForm, DeviceStep1, DeviceStep2, DeviceStep3,
  58 + [Steps.name]: Steps,
  59 + [Steps.Step.name]: Steps.Step, },
  60 + props: {
  61 + userData: { type: Object },
  62 + },
  63 + setup(props) {
  64 + const state = reactive({
  65 + initStep2: false,
  66 + initStep3: false,
  67 + });
  68 + const current = ref(0);
  69 + const isUpdate = ref(true);
  70 + const modelRef = ref({});
  71 + const getTitle = computed(() => (!unref(isUpdate) ? '新增设备' : '编辑设备'));
  72 + const [
  73 + registerForm,
  74 + {
  75 + // setFieldsValue,
  76 + // setProps
  77 + },
  78 + ] = useForm({
  79 + labelWidth: 120,
  80 + schemas,
  81 + showActionButtonGroup: false,
  82 + actionColOptions: {
  83 + span: 24,
  84 + },
  85 + });
  86 +
  87 + const [register] = useModalInner((data) => {
  88 + isUpdate.value = !!data?.isUpdate;
  89 + data && onDataReceive(data);
  90 + });
  91 +
  92 + function handleStepPrev() {
  93 + current.value--;
  94 + }
  95 + function handleStep1Next(step1Values: any) {
  96 + current.value++;
  97 + state.initStep2 = true;
  98 + console.log(step1Values);
  99 + }
  100 + function handleStep2Next(step2Values: any) {
  101 + current.value++;
  102 + state.initStep3 = true;
  103 + console.log(step2Values);
  104 + }
  105 + function handleRedo() {
  106 + current.value = 0;
  107 + state.initSetp2 = false;
  108 + state.initSetp3 = false;
  109 + }
  110 +
  111 +
  112 + function onDataReceive(data) {
  113 + console.log('Data Received', data);
  114 + // 方式1;
  115 + // setFieldsValue({
  116 + // field2: data.data,
  117 + // field1: data.info,
  118 + // });
  119 +
  120 + // // 方式2
  121 + modelRef.value = { field2: data.data, field1: data.info };
  122 +
  123 + // setProps({
  124 + // model:{ field2: data.data, field1: data.info }
  125 + // })
  126 + }
  127 +
  128 + function handleVisibleChange(v) {
  129 + v && props.userData && nextTick(() => onDataReceive(props.userData));
  130 + }
  131 +
  132 + return { register, schemas, registerForm, model: modelRef, getTitle,handleVisibleChange,
  133 + current, ...toRefs(state), handleStepPrev, handleStep1Next, handleStep2Next, handleRedo};
  134 + },
  135 + });
  136 +</script>
... ...
src/views/device/device.data.ts renamed from src/views/device/config.data.ts
1 1 import { BasicColumn } from '/@/components/Table';
2 2 import { FormSchema } from '/@/components/Table';
3 3 import {findDictItemByCode} from "/@/api/system/dict";
4   -import {MessageEnum} from "/@/enums/messageEnum";
5 4 import {DeviceTypeEnum,DeviceState} from "/@/api/device/model/deviceModel";
6 5 export const columns: BasicColumn[] = [
7 6 {
8 7 title: '设备名称',
9 8 dataIndex: 'name',
10   - width: 200,
  9 + width: 120,
11 10 },
12 11 {
13 12 title: '设备类型',
14 13 dataIndex: 'deviceType',
15   - width: 200,
  14 + width: 100,
16 15 slots:{customRender:'deviceType'},
17 16 },
18 17 {
19 18 title: '设备配置',
20 19 dataIndex: 'deviceProfile.name',
21   - width: 180,
  20 + width: 160,
22 21 slots: { customRender: 'deviceProfile' },
23 22 },
  23 +
  24 + {
  25 + title: '所属组织',
  26 + dataIndex: 'organizationId',
  27 + slots: { customRender: 'organizationId' },
  28 + },
24 29 {
25 30 title: '标签',
26 31 dataIndex: 'label',
27 32 width: 180
28 33 },
29 34 {
30   - title: '配置信息',
31   - dataIndex: 'deviceInfo',
32   - width: 180,
33   - slots: { customRender: 'config' },
34   - },
35   - {
36 35 title: '状态',
37 36 dataIndex: 'deviceState',
38 37 width: 120,
... ... @@ -44,11 +43,6 @@ export const columns: BasicColumn[] = [
44 43 dataIndex: 'lastConnectTime',
45 44 width: 180,
46 45 },
47   - {
48   - title: '创建时间',
49   - dataIndex: 'createTime',
50   - width: 180,
51   - },
52 46 ];
53 47
54 48 export const searchFormSchema: FormSchema[] = [
... ... @@ -87,116 +81,43 @@ export const searchFormSchema: FormSchema[] = [
87 81 ];
88 82
89 83
90   -export const isMessage = (type:string)=>{
91   - return type===MessageEnum.IS_SMS;
92   -}
93   -export const isEmail = (type:string)=>{
94   - return type===MessageEnum.IS_EMAIL;
95   -}
96   -
97 84 export const formSchema: FormSchema[] = [
98 85 {
99   - field: 'configName',
100   - label: '配置名称',
101   - required: true,
102   - component:'Input'
  86 + field: 'icon',
  87 + label: '设备图片: ',
  88 + slot: 'iconSelect',
  89 + component: 'Input',
103 90 },
104 91 {
105   - field: 'messageType',
106   - label: '消息类型',
  92 + field: 'name',
  93 + label: '设备名称',
107 94 required: true,
108   - component: 'ApiSelect',
109   - componentProps: {
110   - api:findDictItemByCode,
111   - params:{
112   - dictCode:"message_type"
113   - },
114   - labelField:'itemText',
115   - valueField:'itemValue',
116   - },
  95 + component:'Input',
  96 + componentProps:{
  97 + maxLength:30
  98 + }
117 99 },
118 100 {
119   - field: 'platformType',
120   - label: '平台类型',
  101 + field: 'deviceType',
  102 + label: '设备类型',
121 103 required: true,
122 104 component: 'ApiSelect',
123 105 componentProps: {
124 106 api:findDictItemByCode,
125 107 params:{
126   - dictCode:"platform_type"
  108 + dictCode:"device_type"
127 109 },
128 110 labelField:'itemText',
129 111 valueField:'itemValue',
130 112 },
131   - ifShow:({values}) => isMessage(Reflect.get(values,'messageType')),
132   - },
133   - {
134   - field: 'accessKeyId',
135   - label: 'accessKeyId',
136   - required: true,
137   - component:'Input',
138   - ifShow:({values}) => isMessage(Reflect.get(values,'messageType')),
139   - },
140   - {
141   - field: 'accessKeySecret',
142   - label: 'accessKeySecret',
143   - required: true,
144   - component:'Input',
145   - ifShow:({values}) => isMessage(Reflect.get(values,'messageType')),
146 113 },
147 114 {
148   - field: 'host',
149   - label: '服务器地址',
150   - defaultValue:'smtp.163.com',
151   - required: true,
  115 + field: 'label',
  116 + label: '设备标签',
152 117 component:'Input',
153   - ifShow:({values}) => isEmail(Reflect.get(values,'messageType')),
154   - },
155   - {
156   - field: 'port',
157   - label: '端口',
158   - defaultValue: 25,
159   - required: true,
160   - component:'InputNumber',
161   - ifShow:({values}) => isEmail(Reflect.get(values,'messageType')),
162   - },
163   - {
164   - field: 'username',
165   - label: '用户名',
166   - required: true,
167   - component:'Input',
168   - ifShow:({values}) => isEmail(Reflect.get(values,'messageType')),
169   - },
170   - {
171   - field: 'password',
172   - label: '密码',
173   - required: true,
174   - component:'InputPassword',
175   - ifShow:({values}) => isEmail(Reflect.get(values,'messageType')),
176   - },
177   - {
178   - field: 'config',
179   - label: '消息配置',
180   - component:'Input',
181   - show:false,
182   - },
183   - {
184   - field: 'id',
185   - label: '主键',
186   - component:'Input',
187   - show:false,
188   - },
189   - {
190   - field: 'status',
191   - label: '状态',
192   - component: 'RadioButtonGroup',
193   - defaultValue: 0,
194   - componentProps: {
195   - options: [
196   - { label: '启用', value: 1 },
197   - { label: '停用', value: 0 },
198   - ],
199   - },
  118 + componentProps:{
  119 + maxLength:255
  120 + }
200 121 },
201 122 {
202 123 label: '备注',
... ...
1 1 <template>
2   - <div>
3   - <BasicTable @register="registerTable">
  2 + <PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
  3 + <OrganizationIdTree class="w-1/6 xl:w-1/5" @select="handleSelect" />
  4 + <BasicTable @register="registerTable" class="w-5/6 xl:w-4/5">
4 5 <template #toolbar>
5 6 <a-button type="primary" @click="handleCreate"> 新增设备 </a-button>
6 7 </template>
7   - <template #config="{record}">
8   - <a-button type="link" class="ml-2" @click="showData(record)"> 查看配置 </a-button>
9   - </template>
10 8 <template #deviceProfile="{record}">
11 9 <a-button type="link" class="ml-2" @click="goDeviceProfile"> {{record.deviceProfile.name}} </a-button>
12 10 </template>
  11 + <template #organizationId = "{record}">
  12 + {{record.organizationDTO.name}}
  13 + </template>
13 14 <template #deviceType = "{record}">
14 15 <Tag color="success" class="ml-2">
15 16 {{record.deviceType==DeviceTypeEnum.GATEWAY ?'网关设备':
... ... @@ -44,29 +45,38 @@
44 45 </template>
45 46 </BasicTable>
46 47 <ConfigDrawer @register="registerDrawer" @success="handleSuccess" />
47   - </div>
  48 + <DeviceModal @register="registerModal" @success="handleSuccess"></DeviceModal>
  49 + </PageWrapper>
48 50 </template>
49 51 <script lang="ts">
50   -import { defineComponent,h} from 'vue';
51   -import {DeviceState, DeviceTypeEnum} from "/@/api/device/model/deviceModel";
52   -import { BasicTable, useTable, TableAction } from '/@/components/Table';
53   -import { useDrawer } from '/@/components/Drawer';
54   -import ConfigDrawer from './DeviceDrawer.vue';
55   -import { columns, searchFormSchema } from './config.data';
56   -import {Modal, Tag} from 'ant-design-vue';
57   -import { CodeEditor,JsonPreview } from '/@/components/CodeEditor';
58   -import {useMessage} from "/@/hooks/web/useMessage";
59   -import {deleteDevice, devicePage} from "/@/api/device/deviceManager";
60   -import {PageEnum} from "/@/enums/pageEnum";
61   -import {useGo} from "/@/hooks/web/usePage";
  52 +import {defineComponent, reactive,} from 'vue';
  53 + import { DeviceState, DeviceTypeEnum } from "/@/api/device/model/deviceModel";
  54 + import { BasicTable, useTable, TableAction } from '/@/components/Table';
  55 + import { useDrawer } from '/@/components/Drawer';
  56 + import ConfigDrawer from './DeviceDrawer.vue';
  57 + import { columns, searchFormSchema } from './device.data';
  58 + import { Tag } from 'ant-design-vue';
  59 + import { CodeEditor } from '/@/components/CodeEditor';
  60 + import { useMessage } from "/@/hooks/web/useMessage";
  61 + import { deleteDevice, devicePage } from "/@/api/device/deviceManager";
  62 + import { PageEnum } from "/@/enums/pageEnum";
  63 + import { useGo } from "/@/hooks/web/usePage";
  64 + import { PageWrapper } from "/@/components/Page";
  65 + import OrganizationIdTree from "/@/views/common/OrganizationIdTree.vue";
  66 + import { useModal } from "/@/components/Modal";
  67 + import DeviceModal from "/@/views/device/DeviceModal.vue";
  68 +
62 69
63 70 export default defineComponent({
64 71 name: 'DeviceManagement',
65   - components: { BasicTable, ConfigDrawer, TableAction ,CodeEditor,Tag},
  72 + components: { BasicTable, ConfigDrawer,PageWrapper, TableAction ,OrganizationIdTree,CodeEditor,Tag,
  73 + DeviceModal},
66 74 setup() {
67 75 const [registerDrawer, { openDrawer }] = useDrawer();
68 76 const {createMessage} = useMessage();
69 77 const go = useGo();
  78 + const searchInfo = reactive<Recordable>({});
  79 + const [registerModal, { openModal }] = useModal();
70 80 const [registerTable, { reload }] = useTable({
71 81 title: '设备列表',
72 82 api: devicePage,
... ... @@ -79,6 +89,7 @@ export default defineComponent({
79 89 showTableSetting: true,
80 90 bordered: true,
81 91 showIndexColumn: false,
  92 + searchInfo:searchInfo,
82 93 actionColumn: {
83 94 width: 180,
84 95 title: '操作',
... ... @@ -89,9 +100,12 @@ export default defineComponent({
89 100 });
90 101
91 102 function handleCreate() {
92   - openDrawer(true, {
  103 + // openDrawer(true, {
  104 + // isUpdate: false,
  105 + // });
  106 + openModal(true,{
93 107 isUpdate: false,
94   - });
  108 + })
95 109 }
96 110
97 111 function handleEdit(record: Recordable) {
... ... @@ -112,12 +126,9 @@ export default defineComponent({
112 126 function handleSuccess() {
113 127 reload();
114 128 }
115   - function showData(record: Recordable){
116   - Modal.info({
117   - title: '当前配置',
118   - width:480,
119   - content: h(JsonPreview, { data: JSON.parse(JSON.stringify(record.deviceInfo)) }),
120   - });
  129 + function handleSelect(organization) {
  130 + searchInfo.organizationId = organization;
  131 + handleSuccess();
121 132 }
122 133 function goDeviceProfile(){
123 134 go(PageEnum.DEVICE_PROFILE)
... ... @@ -125,14 +136,16 @@ export default defineComponent({
125 136 return {
126 137 registerTable,
127 138 registerDrawer,
128   - showData,
129 139 handleCreate,
130 140 handleEdit,
131 141 handleDelete,
132 142 handleSuccess,
133 143 goDeviceProfile,
134 144 DeviceTypeEnum,
135   - DeviceState
  145 + DeviceState,
  146 + handleSelect,
  147 + searchInfo,
  148 + registerModal
136 149 };
137 150 },
138 151 });
... ...
  1 +<template>
  2 + <div class="step1">
  3 + <div class="step1-form">
  4 + <BasicForm @register="register">
  5 + <template #iconSelect>
  6 + <Upload
  7 + name="avatar"
  8 + list-type="picture-card"
  9 + class="avatar-uploader"
  10 + :show-upload-list="false"
  11 + :customRequest="customUpload"
  12 + :before-upload="beforeUpload"
  13 + >
  14 + <img v-if="devicePic" :src="devicePic" alt="avatar"/>
  15 + <div v-else>
  16 + <loading-outlined v-if="loading"></loading-outlined>
  17 + <plus-outlined v-else></plus-outlined>
  18 + <div class="ant-upload-text">图片上传</div>
  19 + </div>
  20 + </Upload>
  21 + </template>
  22 + </BasicForm>
  23 + </div>
  24 + </div>
  25 +</template>
  26 +<script lang="ts">
  27 +import {defineComponent, ref} from 'vue';
  28 + import { BasicForm, useForm } from '/@/components/Form';
  29 + import { step1Schemas } from './data';
  30 + import {Select, Input, Divider, Upload, message} from 'ant-design-vue';
  31 + import {upload} from "/@/api/oss/ossFileUploader";
  32 + import {FileItem} from "/@/components/Upload/src/typing";
  33 + export default defineComponent({
  34 + components: {
  35 + BasicForm,
  36 + [Select.name]: Select,
  37 + ASelectOption: Select.Option,
  38 + [Input.name]: Input,
  39 + [Input.Group.name]: Input.Group,
  40 + [Divider.name]: Divider,
  41 + Upload
  42 + },
  43 + emits: ['next'],
  44 + setup(_, { emit }) {
  45 + const devicePic = ref("");
  46 + const [register, { validate }] = useForm({
  47 + labelWidth: 100,
  48 + schemas: step1Schemas,
  49 + actionColOptions: {
  50 + span: 14,
  51 + },
  52 + showResetButton: false,
  53 + submitButtonOptions: {
  54 + text: '下一步',
  55 + },
  56 + submitFunc: customSubmitFunc,
  57 + });
  58 +
  59 + async function customSubmitFunc() {
  60 + try {
  61 + const values = await validate();
  62 + emit('next', values);
  63 + } catch (error) {}
  64 + }
  65 + async function customUpload({file}) {
  66 + if (beforeUpload(file)) {
  67 + const formData = new FormData()
  68 + formData.append('file', file)
  69 + const response = await upload(formData);
  70 + if (response.fileStaticUri) {
  71 + devicePic.value = response.fileStaticUri;
  72 + }
  73 + }
  74 + }
  75 +
  76 + const beforeUpload = (file: FileItem) => {
  77 + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  78 + if (!isJpgOrPng) {
  79 + message.error('只能上传图片文件!');
  80 + }
  81 + const isLt2M = file.size as number / 1024 / 1024 < 2;
  82 + if (!isLt2M) {
  83 + message.error('图片大小不能超过2MB!');
  84 + }
  85 + return isJpgOrPng && isLt2M;
  86 + };
  87 +
  88 + return { register, beforeUpload, customUpload, devicePic };
  89 + },
  90 + });
  91 +</script>
  92 +<style lang="less" scoped>
  93 + .step1 {
  94 + &-form {
  95 + width: 450px;
  96 + margin: 0 auto;
  97 + }
  98 +
  99 + h3 {
  100 + margin: 0 0 12px;
  101 + font-size: 16px;
  102 + line-height: 32px;
  103 + color: @text-color;
  104 + }
  105 +
  106 + h4 {
  107 + margin: 0 0 4px;
  108 + font-size: 14px;
  109 + line-height: 22px;
  110 + color: @text-color;
  111 + }
  112 +
  113 + p {
  114 + color: @text-color;
  115 + }
  116 + }
  117 +
  118 + .pay-select {
  119 + width: 20%;
  120 + }
  121 +
  122 + .pay-input {
  123 + width: 70%;
  124 + }
  125 +</style>
... ...
  1 +<template>
  2 + <div class="step2">
  3 + <a-alert message="确认转账后,资金将直接打入对方账户,无法退回。" show-icon />
  4 + <a-descriptions :column="1" class="mt-5">
  5 + <a-descriptions-item label="付款账户"> ant-design@alipay.com </a-descriptions-item>
  6 + <a-descriptions-item label="收款账户"> test@example.com </a-descriptions-item>
  7 + <a-descriptions-item label="收款人姓名"> Vben </a-descriptions-item>
  8 + <a-descriptions-item label="转账金额"> 500元 </a-descriptions-item>
  9 + </a-descriptions>
  10 + <a-divider />
  11 + <BasicForm @register="register" />
  12 + </div>
  13 +</template>
  14 +<script lang="ts">
  15 + import { defineComponent } from 'vue';
  16 + import { BasicForm, useForm } from '/@/components/Form';
  17 + import { step2Schemas } from './data';
  18 + import { Alert, Divider, Descriptions } from 'ant-design-vue';
  19 +
  20 + export default defineComponent({
  21 + components: {
  22 + BasicForm,
  23 + [Alert.name]: Alert,
  24 + [Divider.name]: Divider,
  25 + [Descriptions.name]: Descriptions,
  26 + [Descriptions.Item.name]: Descriptions.Item,
  27 + },
  28 + emits: ['next', 'prev'],
  29 + setup(_, { emit }) {
  30 + const [register, { validate, setProps }] = useForm({
  31 + labelWidth: 80,
  32 + schemas: step2Schemas,
  33 + actionColOptions: {
  34 + span: 14,
  35 + },
  36 + resetButtonOptions: {
  37 + text: '上一步',
  38 + },
  39 + submitButtonOptions: {
  40 + text: '提交',
  41 + },
  42 + resetFunc: customResetFunc,
  43 + submitFunc: customSubmitFunc,
  44 + });
  45 +
  46 + async function customResetFunc() {
  47 + emit('prev');
  48 + }
  49 +
  50 + async function customSubmitFunc() {
  51 + try {
  52 + const values = await validate();
  53 + setProps({
  54 + submitButtonOptions: {
  55 + loading: true,
  56 + },
  57 + });
  58 + setTimeout(() => {
  59 + setProps({
  60 + submitButtonOptions: {
  61 + loading: false,
  62 + },
  63 + });
  64 + emit('next', values);
  65 + }, 1500);
  66 + } catch (error) {}
  67 + }
  68 +
  69 + return { register };
  70 + },
  71 + });
  72 +</script>
  73 +<style lang="less" scoped>
  74 + .step2 {
  75 + width: 450px;
  76 + margin: 0 auto;
  77 + }
  78 +</style>
... ...
  1 +<template>
  2 + <div class="step3">
  3 + <a-result status="success" title="操作成功" sub-title="预计两小时内到账">
  4 + <template #extra>
  5 + <a-button type="primary" @click="redo"> 再转一笔 </a-button>
  6 + <a-button> 查看账单 </a-button>
  7 + </template>
  8 + </a-result>
  9 + <div class="desc-wrap">
  10 + <a-descriptions :column="1" class="mt-5">
  11 + <a-descriptions-item label="付款账户"> ant-design@alipay.com </a-descriptions-item>
  12 + <a-descriptions-item label="收款账户"> test@example.com </a-descriptions-item>
  13 + <a-descriptions-item label="收款人姓名"> Vben </a-descriptions-item>
  14 + <a-descriptions-item label="转账金额"> 500元 </a-descriptions-item>
  15 + </a-descriptions>
  16 + </div>
  17 + </div>
  18 +</template>
  19 +<script lang="ts">
  20 + import { defineComponent } from 'vue';
  21 + import { Result, Descriptions } from 'ant-design-vue';
  22 + export default defineComponent({
  23 + components: {
  24 + [Result.name]: Result,
  25 + [Descriptions.name]: Descriptions,
  26 + [Descriptions.Item.name]: Descriptions.Item,
  27 + },
  28 + emits: ['redo'],
  29 + setup(_, { emit }) {
  30 + return {
  31 + redo: () => {
  32 + emit('redo');
  33 + },
  34 + };
  35 + },
  36 + });
  37 +</script>
  38 +<style lang="less" scoped>
  39 + .step3 {
  40 + width: 600px;
  41 + margin: 0 auto;
  42 + }
  43 +
  44 + .desc-wrap {
  45 + padding: 24px 40px;
  46 + margin-top: 24px;
  47 + background-color: @background-color-light;
  48 + }
  49 +</style>
... ...
  1 +<template>
  2 + <PageWrapper
  3 + title="分步表单"
  4 + contentBackground
  5 + content=" 将一个冗长或用户不熟悉的表单任务分成多个步骤,指导用户完成。"
  6 + contentClass="p-4"
  7 + >
  8 + <div class="step-form-form">
  9 + <a-steps :current="current">
  10 + <a-step title="填写转账信息" />
  11 + <a-step title="确认转账信息" />
  12 + <a-step title="完成" />
  13 + </a-steps>
  14 + </div>
  15 + <div class="mt-5">
  16 + <Step1 @next="handleStep1Next" v-show="current === 0" />
  17 + <Step2
  18 + @prev="handleStepPrev"
  19 + @next="handleStep2Next"
  20 + v-show="current === 1"
  21 + v-if="initSetp2"
  22 + />
  23 + <Step3 v-show="current === 2" @redo="handleRedo" v-if="initSetp3" />
  24 + </div>
  25 + </PageWrapper>
  26 +</template>
  27 +<script lang="ts">
  28 + import { defineComponent, ref, reactive, toRefs } from 'vue';
  29 + import Step1 from './DeviceStep1.vue';
  30 + import Step2 from './DeviceStep2.vue';
  31 + import Step3 from './DeviceStep3.vue';
  32 + import { PageWrapper } from '/@/components/Page';
  33 + import { Steps } from 'ant-design-vue';
  34 +
  35 + export default defineComponent({
  36 + name: 'FormStepPage',
  37 + components: {
  38 + Step1,
  39 + Step2,
  40 + Step3,
  41 + PageWrapper,
  42 + [Steps.name]: Steps,
  43 + [Steps.Step.name]: Steps.Step,
  44 + },
  45 + setup() {
  46 + const current = ref(0);
  47 +
  48 + const state = reactive({
  49 + initSetp2: false,
  50 + initSetp3: false,
  51 + });
  52 +
  53 + function handleStep1Next(step1Values: any) {
  54 + current.value++;
  55 + state.initSetp2 = true;
  56 + console.log(step1Values);
  57 + }
  58 +
  59 + function handleStepPrev() {
  60 + current.value--;
  61 + }
  62 +
  63 + function handleStep2Next(step2Values: any) {
  64 + current.value++;
  65 + state.initSetp3 = true;
  66 + console.log(step2Values);
  67 + }
  68 +
  69 + function handleRedo() {
  70 + current.value = 0;
  71 + state.initSetp2 = false;
  72 + state.initSetp3 = false;
  73 + }
  74 +
  75 + return {
  76 + current,
  77 + handleStep1Next,
  78 + handleStep2Next,
  79 + handleRedo,
  80 + handleStepPrev,
  81 + ...toRefs(state),
  82 + };
  83 + },
  84 + });
  85 +</script>
  86 +<style lang="less" scoped>
  87 + .step-form-content {
  88 + padding: 24px;
  89 + background-color: @component-background;
  90 + }
  91 +
  92 + .step-form-form {
  93 + width: 750px;
  94 + margin: 0 auto;
  95 + }
  96 +</style>
... ...
  1 +import { FormSchema } from '/@/components/Form';
  2 +import {findDictItemByCode} from "/@/api/system/dict";
  3 +
  4 +export const step1Schemas: FormSchema[] = [
  5 + {
  6 + field: 'icon',
  7 + label: '设备图片: ',
  8 + slot: 'iconSelect',
  9 + component: 'Input',
  10 + },
  11 + {
  12 + field: 'name',
  13 + label: '设备名称',
  14 + required: true,
  15 + component:'Input',
  16 + componentProps:{
  17 + maxLength:30
  18 + }
  19 + },
  20 + {
  21 + field: 'deviceType',
  22 + label: '设备类型',
  23 + required: true,
  24 + component: 'ApiSelect',
  25 + componentProps: {
  26 + api:findDictItemByCode,
  27 + params:{
  28 + dictCode:"device_type"
  29 + },
  30 + labelField:'itemText',
  31 + valueField:'itemValue',
  32 + },
  33 + },
  34 + {
  35 + field: 'label',
  36 + label: '设备标签',
  37 + component:'Input',
  38 + componentProps:{
  39 + maxLength:255
  40 + }
  41 + },
  42 + {
  43 + label: '备注',
  44 + field: 'remark',
  45 + component: 'InputTextArea',
  46 + }
  47 +];
  48 +
  49 +export const step2Schemas: FormSchema[] = [
  50 + {
  51 + field: 'pwd',
  52 + component: 'InputPassword',
  53 + label: '支付密码',
  54 + required: true,
  55 + defaultValue: '123456',
  56 + },
  57 +];
... ...