Showing
9 changed files
with
773 additions
and
32 deletions
@@ -7,26 +7,49 @@ | @@ -7,26 +7,49 @@ | ||
7 | width="500px" | 7 | width="500px" |
8 | @ok="handleSubmit" | 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" /> | ||
23 | + <plus-outlined v-else /> | ||
24 | + <div class="ant-upload-text">图片上传</div> | ||
25 | + </div> | ||
26 | + </Upload> | ||
27 | + </template> | ||
28 | + </BasicForm> | ||
11 | </BasicDrawer> | 29 | </BasicDrawer> |
12 | </template> | 30 | </template> |
13 | <script lang="ts"> | 31 | <script lang="ts"> |
14 | import { defineComponent, ref, computed, unref } from 'vue'; | 32 | import { defineComponent, ref, computed, unref } from 'vue'; |
15 | import { BasicForm, useForm } from '/@/components/Form'; | 33 | import { BasicForm, useForm } from '/@/components/Form'; |
16 | - import { formSchema } from './config.data'; | 34 | + import { formSchema } from './device.data'; |
17 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | 35 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; |
36 | + | ||
18 | import { saveOrEditMessageConfig } from '/@/api/message/config'; | 37 | import { saveOrEditMessageConfig } from '/@/api/message/config'; |
19 | import { useMessage } from '/@/hooks/web/useMessage'; | 38 | import { useMessage } from '/@/hooks/web/useMessage'; |
39 | + import { upload } from '/@/api/oss/ossFileUploader'; | ||
40 | + import { message, Upload } from 'ant-design-vue'; | ||
41 | + import { FileItem } from '/@/components/Upload/src/typing'; | ||
20 | 42 | ||
21 | export default defineComponent({ | 43 | export default defineComponent({ |
22 | - name: 'ConfigDrawer', | ||
23 | - components: { BasicDrawer, BasicForm }, | 44 | + name: 'DeviceDrawer', |
45 | + components: { BasicDrawer, BasicForm, Upload }, | ||
24 | emits: ['success', 'register'], | 46 | emits: ['success', 'register'], |
25 | setup(_, { emit }) { | 47 | setup(_, { emit }) { |
26 | const isUpdate = ref(true); | 48 | const isUpdate = ref(true); |
27 | 49 | ||
50 | + const devicePic = ref(''); | ||
28 | const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({ | 51 | const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({ |
29 | - labelWidth: 120, | 52 | + labelWidth: 80, |
30 | schemas: formSchema, | 53 | schemas: formSchema, |
31 | showActionButtonGroup: false, | 54 | showActionButtonGroup: false, |
32 | }); | 55 | }); |
@@ -46,7 +69,7 @@ | @@ -46,7 +69,7 @@ | ||
46 | } | 69 | } |
47 | }); | 70 | }); |
48 | 71 | ||
49 | - const getTitle = computed(() => (!unref(isUpdate) ? '新增消息配置' : '编辑消息配置')); | 72 | + const getTitle = computed(() => (!unref(isUpdate) ? '新增设备' : '编辑设备')); |
50 | 73 | ||
51 | async function handleSubmit() { | 74 | async function handleSubmit() { |
52 | try { | 75 | try { |
@@ -78,13 +101,43 @@ | @@ -78,13 +101,43 @@ | ||
78 | setDrawerProps({ confirmLoading: false }); | 101 | setDrawerProps({ confirmLoading: false }); |
79 | } | 102 | } |
80 | } | 103 | } |
104 | + async function customUpload({ file }) { | ||
105 | + if (beforeUpload(file)) { | ||
106 | + const formData = new FormData(); | ||
107 | + formData.append('file', file); | ||
108 | + const response = await upload(formData); | ||
109 | + if (response.fileStaticUri) { | ||
110 | + devicePic.value = response.fileStaticUri; | ||
111 | + } | ||
112 | + } | ||
113 | + } | ||
81 | 114 | ||
115 | + const beforeUpload = (file: FileItem) => { | ||
116 | + const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; | ||
117 | + if (!isJpgOrPng) { | ||
118 | + message.error('只能上传图片文件!'); | ||
119 | + } | ||
120 | + const isLt2M = (file.size as number) / 1024 / 1024 < 2; | ||
121 | + if (!isLt2M) { | ||
122 | + message.error('图片大小不能超过2MB!'); | ||
123 | + } | ||
124 | + return isJpgOrPng && isLt2M; | ||
125 | + }; | ||
82 | return { | 126 | return { |
83 | registerDrawer, | 127 | registerDrawer, |
84 | registerForm, | 128 | registerForm, |
85 | getTitle, | 129 | getTitle, |
86 | handleSubmit, | 130 | handleSubmit, |
131 | + beforeUpload, | ||
132 | + customUpload, | ||
133 | + devicePic, | ||
87 | }; | 134 | }; |
88 | }, | 135 | }, |
89 | }); | 136 | }); |
90 | </script> | 137 | </script> |
138 | +<style> | ||
139 | + .ant-upload-select-picture-card i { | ||
140 | + font-size: 32px; | ||
141 | + color: #999; | ||
142 | + } | ||
143 | +</style> |
src/views/device/DeviceModal.vue
0 → 100644
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
0 → 100644
1 | +import { BasicColumn } from '/@/components/Table'; | ||
2 | +import { FormSchema } from '/@/components/Table'; | ||
3 | +import {findDictItemByCode} from "/@/api/system/dict"; | ||
4 | +import {DeviceTypeEnum,DeviceState} from "/@/api/device/model/deviceModel"; | ||
5 | +export const columns: BasicColumn[] = [ | ||
6 | + { | ||
7 | + title: '设备名称', | ||
8 | + dataIndex: 'name', | ||
9 | + width: 120, | ||
10 | + }, | ||
11 | + { | ||
12 | + title: '设备类型', | ||
13 | + dataIndex: 'deviceType', | ||
14 | + width: 100, | ||
15 | + slots:{customRender:'deviceType'}, | ||
16 | + }, | ||
17 | + { | ||
18 | + title: '设备配置', | ||
19 | + dataIndex: 'deviceProfile.name', | ||
20 | + width: 160, | ||
21 | + slots: { customRender: 'deviceProfile' }, | ||
22 | + }, | ||
23 | + | ||
24 | + { | ||
25 | + title: '所属组织', | ||
26 | + dataIndex: 'organizationId', | ||
27 | + slots: { customRender: 'organizationId' }, | ||
28 | + }, | ||
29 | + { | ||
30 | + title: '标签', | ||
31 | + dataIndex: 'label', | ||
32 | + width: 180 | ||
33 | + }, | ||
34 | + { | ||
35 | + title: '状态', | ||
36 | + dataIndex: 'deviceState', | ||
37 | + width: 120, | ||
38 | + slots: { customRender: 'deviceState' }, | ||
39 | + }, | ||
40 | + | ||
41 | + { | ||
42 | + title: '最后连接时间', | ||
43 | + dataIndex: 'lastConnectTime', | ||
44 | + width: 180, | ||
45 | + }, | ||
46 | +]; | ||
47 | + | ||
48 | +export const searchFormSchema: FormSchema[] = [ | ||
49 | + { | ||
50 | + field: 'deviceType', | ||
51 | + label: '设备类型', | ||
52 | + component: 'Select', | ||
53 | + componentProps: { | ||
54 | + options: [ | ||
55 | + { label: '网关设备', value: DeviceTypeEnum.GATEWAY }, | ||
56 | + { label: '直连设备', value: DeviceTypeEnum.DIRECT_CONNECTION }, | ||
57 | + { label: '网关子设备', value: DeviceTypeEnum.SENSOR }, | ||
58 | + ], | ||
59 | + }, | ||
60 | + colProps: { span: 4 }, | ||
61 | + }, | ||
62 | + { | ||
63 | + field: 'deviceState', | ||
64 | + label: '设备状态', | ||
65 | + component: 'Select', | ||
66 | + componentProps: { | ||
67 | + options: [ | ||
68 | + { label: '待激活', value: DeviceState.INACTIVE }, | ||
69 | + { label: '在线', value: DeviceState.ONLINE }, | ||
70 | + { label: '离线', value: DeviceState.OFFLINE }, | ||
71 | + ], | ||
72 | + }, | ||
73 | + colProps: { span: 4 }, | ||
74 | + }, | ||
75 | + { | ||
76 | + field: 'name', | ||
77 | + label: '设备名称', | ||
78 | + component: 'Input', | ||
79 | + colProps: { span: 8 }, | ||
80 | + }, | ||
81 | +]; | ||
82 | + | ||
83 | + | ||
84 | +export const formSchema: FormSchema[] = [ | ||
85 | + { | ||
86 | + field: 'icon', | ||
87 | + label: '设备图片: ', | ||
88 | + slot: 'iconSelect', | ||
89 | + component: 'Input', | ||
90 | + }, | ||
91 | + { | ||
92 | + field: 'name', | ||
93 | + label: '设备名称', | ||
94 | + required: true, | ||
95 | + component:'Input', | ||
96 | + componentProps:{ | ||
97 | + maxLength:30 | ||
98 | + } | ||
99 | + }, | ||
100 | + { | ||
101 | + field: 'deviceType', | ||
102 | + label: '设备类型', | ||
103 | + required: true, | ||
104 | + component: 'ApiSelect', | ||
105 | + componentProps: { | ||
106 | + api:findDictItemByCode, | ||
107 | + params:{ | ||
108 | + dictCode:"device_type" | ||
109 | + }, | ||
110 | + labelField:'itemText', | ||
111 | + valueField:'itemValue', | ||
112 | + }, | ||
113 | + }, | ||
114 | + { | ||
115 | + field: 'label', | ||
116 | + label: '设备标签', | ||
117 | + component:'Input', | ||
118 | + componentProps:{ | ||
119 | + maxLength:255 | ||
120 | + } | ||
121 | + }, | ||
122 | + { | ||
123 | + label: '备注', | ||
124 | + field: 'remark', | ||
125 | + component: 'InputTextArea', | ||
126 | + } | ||
127 | +]; |
1 | <template> | 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 | <template #toolbar> | 5 | <template #toolbar> |
5 | <a-button type="primary" @click="handleCreate"> 新增设备 </a-button> | 6 | <a-button type="primary" @click="handleCreate"> 新增设备 </a-button> |
6 | </template> | 7 | </template> |
7 | - <template #config="{ record }"> | ||
8 | - <a-button type="link" class="ml-2" @click="showData(record)"> 查看配置 </a-button> | ||
9 | - </template> | 8 | + |
10 | <template #deviceProfile="{ record }"> | 9 | <template #deviceProfile="{ record }"> |
11 | <a-button type="link" class="ml-2" @click="goDeviceProfile"> | 10 | <a-button type="link" class="ml-2" @click="goDeviceProfile"> |
12 | {{ record.deviceProfile.name }} | 11 | {{ record.deviceProfile.name }} |
13 | </a-button> | 12 | </a-button> |
14 | </template> | 13 | </template> |
14 | + <template #organizationId="{ record }"> | ||
15 | + {{ record.organizationDTO.name }} | ||
16 | + </template> | ||
15 | <template #deviceType="{ record }"> | 17 | <template #deviceType="{ record }"> |
16 | <Tag color="success" class="ml-2"> | 18 | <Tag color="success" class="ml-2"> |
17 | {{ | 19 | {{ |
@@ -65,29 +67,45 @@ | @@ -65,29 +67,45 @@ | ||
65 | </template> | 67 | </template> |
66 | </BasicTable> | 68 | </BasicTable> |
67 | <ConfigDrawer @register="registerDrawer" @success="handleSuccess" /> | 69 | <ConfigDrawer @register="registerDrawer" @success="handleSuccess" /> |
68 | - </div> | 70 | + <DeviceModal @register="registerModal" @success="handleSuccess"></DeviceModal> |
71 | + </PageWrapper> | ||
69 | </template> | 72 | </template> |
70 | <script lang="ts"> | 73 | <script lang="ts"> |
71 | - import { defineComponent, h } from 'vue'; | 74 | + import { defineComponent, reactive } from 'vue'; |
72 | import { DeviceState, DeviceTypeEnum } from '/@/api/device/model/deviceModel'; | 75 | import { DeviceState, DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
73 | import { BasicTable, useTable, TableAction } from '/@/components/Table'; | 76 | import { BasicTable, useTable, TableAction } from '/@/components/Table'; |
74 | import { useDrawer } from '/@/components/Drawer'; | 77 | import { useDrawer } from '/@/components/Drawer'; |
75 | import ConfigDrawer from './DeviceDrawer.vue'; | 78 | import ConfigDrawer from './DeviceDrawer.vue'; |
76 | - import { columns, searchFormSchema } from './config.data'; | ||
77 | - import { Modal, Tag } from 'ant-design-vue'; | ||
78 | - import { JsonPreview } from '/@/components/CodeEditor'; | 79 | + import { columns, searchFormSchema } from './device.data'; |
80 | + import { Tag } from 'ant-design-vue'; | ||
81 | + import { CodeEditor } from '/@/components/CodeEditor'; | ||
79 | import { useMessage } from '/@/hooks/web/useMessage'; | 82 | import { useMessage } from '/@/hooks/web/useMessage'; |
80 | import { deleteDevice, devicePage } from '/@/api/device/deviceManager'; | 83 | import { deleteDevice, devicePage } from '/@/api/device/deviceManager'; |
81 | import { PageEnum } from '/@/enums/pageEnum'; | 84 | import { PageEnum } from '/@/enums/pageEnum'; |
82 | import { useGo } from '/@/hooks/web/usePage'; | 85 | import { useGo } from '/@/hooks/web/usePage'; |
86 | + import { PageWrapper } from '/@/components/Page'; | ||
87 | + import OrganizationIdTree from '/@/views/common/OrganizationIdTree.vue'; | ||
88 | + import { useModal } from '/@/components/Modal'; | ||
89 | + import DeviceModal from '/@/views/device/DeviceModal.vue'; | ||
83 | 90 | ||
84 | export default defineComponent({ | 91 | export default defineComponent({ |
85 | name: 'DeviceManagement', | 92 | name: 'DeviceManagement', |
86 | - components: { BasicTable, ConfigDrawer, TableAction, Tag }, | 93 | + components: { |
94 | + BasicTable, | ||
95 | + ConfigDrawer, | ||
96 | + PageWrapper, | ||
97 | + TableAction, | ||
98 | + OrganizationIdTree, | ||
99 | + CodeEditor, | ||
100 | + Tag, | ||
101 | + DeviceModal, | ||
102 | + }, | ||
87 | setup() { | 103 | setup() { |
88 | - const go = useGo(); | ||
89 | - const { createMessage } = useMessage(); | ||
90 | const [registerDrawer, { openDrawer }] = useDrawer(); | 104 | const [registerDrawer, { openDrawer }] = useDrawer(); |
105 | + const { createMessage } = useMessage(); | ||
106 | + const go = useGo(); | ||
107 | + const searchInfo = reactive<Recordable>({}); | ||
108 | + const [registerModal, { openModal }] = useModal(); | ||
91 | const [registerTable, { reload }] = useTable({ | 109 | const [registerTable, { reload }] = useTable({ |
92 | title: '设备列表', | 110 | title: '设备列表', |
93 | api: devicePage, | 111 | api: devicePage, |
@@ -100,6 +118,7 @@ | @@ -100,6 +118,7 @@ | ||
100 | showTableSetting: true, | 118 | showTableSetting: true, |
101 | bordered: true, | 119 | bordered: true, |
102 | showIndexColumn: false, | 120 | showIndexColumn: false, |
121 | + searchInfo: searchInfo, | ||
103 | actionColumn: { | 122 | actionColumn: { |
104 | width: 180, | 123 | width: 180, |
105 | title: '操作', | 124 | title: '操作', |
@@ -108,20 +127,23 @@ | @@ -108,20 +127,23 @@ | ||
108 | fixed: undefined, | 127 | fixed: undefined, |
109 | }, | 128 | }, |
110 | }); | 129 | }); |
111 | - // 新增 | 130 | + |
112 | function handleCreate() { | 131 | function handleCreate() { |
113 | - openDrawer(true, { | 132 | + // openDrawer(true, { |
133 | + // isUpdate: false, | ||
134 | + // }); | ||
135 | + openModal(true, { | ||
114 | isUpdate: false, | 136 | isUpdate: false, |
115 | }); | 137 | }); |
116 | } | 138 | } |
117 | - // 更新 | 139 | + |
118 | function handleEdit(record: Recordable) { | 140 | function handleEdit(record: Recordable) { |
119 | openDrawer(true, { | 141 | openDrawer(true, { |
120 | record, | 142 | record, |
121 | isUpdate: true, | 143 | isUpdate: true, |
122 | }); | 144 | }); |
123 | } | 145 | } |
124 | - // 删除 | 146 | + |
125 | function handleDelete(record: Recordable) { | 147 | function handleDelete(record: Recordable) { |
126 | let ids = [record.id]; | 148 | let ids = [record.id]; |
127 | deleteDevice(ids).then(() => { | 149 | deleteDevice(ids).then(() => { |
@@ -129,17 +151,13 @@ | @@ -129,17 +151,13 @@ | ||
129 | handleSuccess(); | 151 | handleSuccess(); |
130 | }); | 152 | }); |
131 | } | 153 | } |
132 | - // 刷新 | 154 | + |
133 | function handleSuccess() { | 155 | function handleSuccess() { |
134 | reload(); | 156 | reload(); |
135 | } | 157 | } |
136 | - // 查看某一个设备具体信息 | ||
137 | - function showData(record: Recordable) { | ||
138 | - Modal.info({ | ||
139 | - title: '当前配置', | ||
140 | - width: 480, | ||
141 | - content: h(JsonPreview, { data: JSON.parse(JSON.stringify(record.deviceInfo)) }), | ||
142 | - }); | 158 | + function handleSelect(organization) { |
159 | + searchInfo.organizationId = organization; | ||
160 | + handleSuccess(); | ||
143 | } | 161 | } |
144 | function goDeviceProfile() { | 162 | function goDeviceProfile() { |
145 | go(PageEnum.DEVICE_PROFILE); | 163 | go(PageEnum.DEVICE_PROFILE); |
@@ -147,7 +165,6 @@ | @@ -147,7 +165,6 @@ | ||
147 | return { | 165 | return { |
148 | registerTable, | 166 | registerTable, |
149 | registerDrawer, | 167 | registerDrawer, |
150 | - showData, | ||
151 | handleCreate, | 168 | handleCreate, |
152 | handleEdit, | 169 | handleEdit, |
153 | handleDelete, | 170 | handleDelete, |
@@ -155,6 +172,9 @@ | @@ -155,6 +172,9 @@ | ||
155 | goDeviceProfile, | 172 | goDeviceProfile, |
156 | DeviceTypeEnum, | 173 | DeviceTypeEnum, |
157 | DeviceState, | 174 | DeviceState, |
175 | + handleSelect, | ||
176 | + searchInfo, | ||
177 | + registerModal, | ||
158 | }; | 178 | }; |
159 | }, | 179 | }, |
160 | }); | 180 | }); |
src/views/device/step/DeviceStep1.vue
0 → 100644
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> |
src/views/device/step/DeviceStep2.vue
0 → 100644
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> |
src/views/device/step/DeviceStep3.vue
0 → 100644
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> |
src/views/device/step/StepIndex.vue
0 → 100644
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> |
src/views/device/step/data.tsx
0 → 100644
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 | +]; |