Commit a1ae6e5a14ecb6653fee40502319206425ade1fa
Merge branch 'sqy_dev' into 'main'
'feat:设备分配客户,oem按钮调整,地图铆钉不显示,账号详情404问题' See merge request huang/yun-teng-iot-front!80
Showing
16 changed files
with
188 additions
and
28 deletions
| ... | ... | @@ -136,3 +136,35 @@ export const saveDeviceToken = (data) => { |
| 136 | 136 | } |
| 137 | 137 | ); |
| 138 | 138 | }; |
| 139 | + | |
| 140 | +// 获取当前租户下的客户列表 | |
| 141 | +export const getCustomerList = (params) => { | |
| 142 | + return defHttp.get({ | |
| 143 | + url: '/user/customers/' + params.organizationId, | |
| 144 | + }); | |
| 145 | +}; | |
| 146 | + | |
| 147 | +// 分配客户或 | |
| 148 | +export const dispatchCustomer = (data) => { | |
| 149 | + const { customerId, tbDeviceId } = data; | |
| 150 | + return defHttp.post( | |
| 151 | + { | |
| 152 | + url: `/customer/${customerId}/device/${tbDeviceId}`, | |
| 153 | + }, | |
| 154 | + { | |
| 155 | + joinPrefix: false, | |
| 156 | + } | |
| 157 | + ); | |
| 158 | +}; | |
| 159 | +// 取消分配客户 | |
| 160 | +export const cancelDispatchCustomer = (data) => { | |
| 161 | + const { customerId, tbDeviceId } = data; | |
| 162 | + return defHttp.delete( | |
| 163 | + { | |
| 164 | + url: `/customer/${customerId}/device/${tbDeviceId}`, | |
| 165 | + }, | |
| 166 | + { | |
| 167 | + joinPrefix: false, | |
| 168 | + } | |
| 169 | + ); | |
| 170 | +}; | ... | ... |
| 1 | 1 | import { formatToDateTime } from '/@/utils/dateUtil'; |
| 2 | 2 | import { FormSchema } from '/@/components/Form'; |
| 3 | 3 | import { BasicColumn } from '/@/components/Table'; |
| 4 | - | |
| 5 | 4 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
| 6 | - | |
| 5 | +import { getCustomerList } from '/@/api/device/deviceManager'; | |
| 7 | 6 | export const columns: BasicColumn[] = [ |
| 8 | 7 | { |
| 9 | 8 | title: '设备名称', |
| ... | ... | @@ -287,3 +286,19 @@ export const statusType = (type: string): string => { |
| 287 | 286 | return '激活未确认'; |
| 288 | 287 | } |
| 289 | 288 | }; |
| 289 | + | |
| 290 | +export const customerForm: FormSchema[] = [ | |
| 291 | + { | |
| 292 | + field: 'customerId', | |
| 293 | + label: '分配客户', | |
| 294 | + component: 'ApiSelect', | |
| 295 | + componentProps: { | |
| 296 | + api: getCustomerList, | |
| 297 | + immediate: false, | |
| 298 | + labelField: 'realName', | |
| 299 | + valueField: 'customerId', | |
| 300 | + }, | |
| 301 | + required: true, | |
| 302 | + colProps: { span: 12 }, | |
| 303 | + }, | |
| 304 | +]; | ... | ... |
| 1 | +<template> | |
| 2 | + <BasicModal | |
| 3 | + v-bind="$attrs" | |
| 4 | + @register="registerModal" | |
| 5 | + title="将设备分配给客户" | |
| 6 | + :canFullscreen="false" | |
| 7 | + centered | |
| 8 | + @ok="dispatchCustomer" | |
| 9 | + :minHeight="150" | |
| 10 | + okText="分配" | |
| 11 | + > | |
| 12 | + <BasicForm @register="registerForm" /> | |
| 13 | + </BasicModal> | |
| 14 | +</template> | |
| 15 | + | |
| 16 | +<script lang="ts"> | |
| 17 | + import { defineComponent } from 'vue'; | |
| 18 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | |
| 19 | + import { BasicForm, useForm } from '/@/components/Form'; | |
| 20 | + import { customerForm } from '../../config/detail.config'; | |
| 21 | + import { dispatchCustomer as dispatchCustomerApi } from '/@/api/device/deviceManager'; | |
| 22 | + export default defineComponent({ | |
| 23 | + name: 'AlarmDetailModal', | |
| 24 | + components: { | |
| 25 | + BasicModal, | |
| 26 | + BasicForm, | |
| 27 | + }, | |
| 28 | + emits: ['reload', 'register'], | |
| 29 | + setup(_, { emit }) { | |
| 30 | + let record = {}; | |
| 31 | + const [registerModal, { closeModal }] = useModalInner((data: any) => { | |
| 32 | + const { organizationId } = data; | |
| 33 | + record = data; | |
| 34 | + updateSchema([ | |
| 35 | + { | |
| 36 | + field: 'customerId', | |
| 37 | + componentProps: { | |
| 38 | + params: { organizationId }, | |
| 39 | + }, | |
| 40 | + }, | |
| 41 | + ]); | |
| 42 | + }); | |
| 43 | + const [registerForm, { validate, getFieldsValue, updateSchema, resetFields }] = useForm({ | |
| 44 | + labelWidth: 100, | |
| 45 | + showActionButtonGroup: false, | |
| 46 | + schemas: customerForm, | |
| 47 | + }); | |
| 48 | + // 分配客户 | |
| 49 | + const dispatchCustomer = async () => { | |
| 50 | + await validate(); | |
| 51 | + const { customerId } = getFieldsValue(); | |
| 52 | + await dispatchCustomerApi({ ...record, customerId }); | |
| 53 | + closeModal(); | |
| 54 | + resetFields(); | |
| 55 | + emit('reload'); | |
| 56 | + }; | |
| 57 | + | |
| 58 | + return { | |
| 59 | + registerModal, | |
| 60 | + registerForm, | |
| 61 | + dispatchCustomer, | |
| 62 | + }; | |
| 63 | + }, | |
| 64 | + }); | |
| 65 | +</script> | ... | ... |
| ... | ... | @@ -11,7 +11,12 @@ |
| 11 | 11 | :customRequest="customUpload" |
| 12 | 12 | :before-upload="beforeUpload" |
| 13 | 13 | > |
| 14 | - <img v-if="devicePic" :src="devicePic" alt="avatar" /> | |
| 14 | + <img | |
| 15 | + v-if="devicePic" | |
| 16 | + :src="devicePic" | |
| 17 | + alt="avatar" | |
| 18 | + style="width: 6.25rem; height: 6.25rem" | |
| 19 | + /> | |
| 15 | 20 | <div v-else> |
| 16 | 21 | <PlusOutlined /> |
| 17 | 22 | <div class="ant-upload-text">图片上传</div> |
| ... | ... | @@ -76,7 +81,6 @@ |
| 76 | 81 | [Divider.name]: Divider, |
| 77 | 82 | Upload, |
| 78 | 83 | EnvironmentTwoTone, |
| 79 | - // LoadingOutlined, | |
| 80 | 84 | PlusOutlined, |
| 81 | 85 | Modal, |
| 82 | 86 | [Form.name]: Form, |
| ... | ... | @@ -175,7 +179,8 @@ |
| 175 | 179 | if (!wrapEl) return; |
| 176 | 180 | let preMarker = null; |
| 177 | 181 | const map = new BMap.Map(wrapEl); |
| 178 | - let myIcon = new BMap.Icon('/src/assets/images/wz.png', new BMap.Size(20, 30)); | |
| 182 | + const icon = '/src/assets/images/wz.png'; | |
| 183 | + let myIcon = new BMap.Icon(icon, new BMap.Size(20, 30)); | |
| 179 | 184 | const point = new BMap.Point(Number(longitude), Number(latitude)); |
| 180 | 185 | let marker = new BMap.Marker(point, { icon: myIcon }); |
| 181 | 186 | if (marker) { | ... | ... |
| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | /> |
| 9 | 9 | <BasicTable @register="registerTable" class="w-5/6 xl:w-4/5"> |
| 10 | 10 | <template #toolbar> |
| 11 | - <a-button type="primary" @click="handleCreate"> 新增设备 </a-button> | |
| 11 | + <a-button type="primary" @click="handleCreate" v-if="authBtn(role)"> 新增设备 </a-button> | |
| 12 | 12 | </template> |
| 13 | 13 | <template #deviceProfile="{ record }"> |
| 14 | 14 | <a-button type="link" class="ml-2" @click="goDeviceProfile"> |
| ... | ... | @@ -50,6 +50,23 @@ |
| 50 | 50 | <template #action="{ record }"> |
| 51 | 51 | <TableAction |
| 52 | 52 | :actions="[ |
| 53 | + record.customerId | |
| 54 | + ? { | |
| 55 | + tooltip: '取消分配给客户', | |
| 56 | + icon: 'mdi:account-arrow-left', | |
| 57 | + ifShow: authBtn(role), | |
| 58 | + popConfirm: { | |
| 59 | + title: '是否取消分配给客户', | |
| 60 | + confirm: handleCancelDispatchCustomer.bind(null, record), | |
| 61 | + }, | |
| 62 | + } | |
| 63 | + : { | |
| 64 | + icon: 'mdi:account-arrow-right', | |
| 65 | + tooltip: '分配给客户', | |
| 66 | + ifShow: authBtn(role), | |
| 67 | + onClick: handleDispatchCustomer.bind(null, record), | |
| 68 | + }, | |
| 69 | + | |
| 53 | 70 | { |
| 54 | 71 | label: '详情', |
| 55 | 72 | icon: 'ant-design:eye-outlined', |
| ... | ... | @@ -58,11 +75,13 @@ |
| 58 | 75 | { |
| 59 | 76 | label: '编辑', |
| 60 | 77 | icon: 'clarity:note-edit-line', |
| 78 | + ifShow: authBtn(role), | |
| 61 | 79 | onClick: handleEdit.bind(null, record), |
| 62 | 80 | }, |
| 63 | 81 | { |
| 64 | 82 | label: '删除', |
| 65 | 83 | icon: 'ant-design:delete-outlined', |
| 84 | + ifShow: authBtn(role), | |
| 66 | 85 | color: 'error', |
| 67 | 86 | popConfirm: { |
| 68 | 87 | title: '是否确认删除', |
| ... | ... | @@ -74,7 +93,8 @@ |
| 74 | 93 | </template> |
| 75 | 94 | </BasicTable> |
| 76 | 95 | <DeviceDetailDrawer @register="registerDetailDrawer" /> |
| 77 | - <DeviceModal @register="registerModal" @success="handleSuccess" @reload="handleReload" /> | |
| 96 | + <DeviceModal @register="registerModal" @success="handleSuccess" @reload="handleSuccess" /> | |
| 97 | + <CustomerModal @register="registerCustomerModal" @reload="handleSuccess" /> | |
| 78 | 98 | </PageWrapper> |
| 79 | 99 | </div> |
| 80 | 100 | </template> |
| ... | ... | @@ -85,7 +105,7 @@ |
| 85 | 105 | import { columns, searchFormSchema } from './config/device.data'; |
| 86 | 106 | import { Tag } from 'ant-design-vue'; |
| 87 | 107 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 88 | - import { deleteDevice, devicePage } from '/@/api/device/deviceManager'; | |
| 108 | + import { deleteDevice, devicePage, cancelDispatchCustomer } from '/@/api/device/deviceManager'; | |
| 89 | 109 | import { PageEnum } from '/@/enums/pageEnum'; |
| 90 | 110 | import { useGo } from '/@/hooks/web/usePage'; |
| 91 | 111 | import { PageWrapper } from '/@/components/Page'; |
| ... | ... | @@ -95,7 +115,11 @@ |
| 95 | 115 | import DeviceModal from './cpns/modal/DeviceModal.vue'; |
| 96 | 116 | import { useDrawer } from '/@/components/Drawer'; |
| 97 | 117 | import DeviceDetailDrawer from './cpns/modal/DeviceDetailDrawer.vue'; |
| 118 | + import CustomerModal from './cpns/modal/CustomerModal.vue'; | |
| 98 | 119 | |
| 120 | + import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | |
| 121 | + import { getAuthCache } from '/@/utils/auth'; | |
| 122 | + import { authBtn } from '/@/enums/roleEnum'; | |
| 99 | 123 | export default defineComponent({ |
| 100 | 124 | name: 'DeviceManagement', |
| 101 | 125 | components: { |
| ... | ... | @@ -106,6 +130,7 @@ |
| 106 | 130 | Tag, |
| 107 | 131 | DeviceModal, |
| 108 | 132 | DeviceDetailDrawer, |
| 133 | + CustomerModal, | |
| 109 | 134 | }, |
| 110 | 135 | setup(_) { |
| 111 | 136 | const { createMessage } = useMessage(); |
| ... | ... | @@ -114,6 +139,7 @@ |
| 114 | 139 | const searchInfo = reactive<Recordable>({}); |
| 115 | 140 | const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); |
| 116 | 141 | const [registerModal, { openModal }] = useModal(); |
| 142 | + const [registerCustomerModal, { openModal: openCustomerModal }] = useModal(); | |
| 117 | 143 | const [registerDetailDrawer, { openDrawer }] = useDrawer(); |
| 118 | 144 | const [registerTable, { reload }] = useTable({ |
| 119 | 145 | title: '设备列表', |
| ... | ... | @@ -130,22 +156,32 @@ |
| 130 | 156 | showIndexColumn: false, |
| 131 | 157 | searchInfo: searchInfo, |
| 132 | 158 | actionColumn: { |
| 133 | - width: 200, | |
| 159 | + width: 250, | |
| 134 | 160 | title: '操作', |
| 135 | 161 | dataIndex: 'action', |
| 136 | 162 | slots: { customRender: 'action' }, |
| 137 | 163 | fixed: 'right', |
| 138 | 164 | }, |
| 139 | 165 | }); |
| 140 | - const handleReload = () => { | |
| 141 | - handleSuccess(); | |
| 142 | - }; | |
| 166 | + | |
| 167 | + const userInfo: any = getAuthCache(USER_INFO_KEY); | |
| 168 | + const role: string = userInfo.roles[0]; | |
| 143 | 169 | |
| 144 | 170 | function handleCreate() { |
| 145 | 171 | openModal(true, { |
| 146 | 172 | isUpdate: false, |
| 147 | 173 | }); |
| 148 | 174 | } |
| 175 | + // 分配客户 | |
| 176 | + function handleDispatchCustomer(record: Recordable) { | |
| 177 | + openCustomerModal(true, record); | |
| 178 | + } | |
| 179 | + // 取消分配客户 | |
| 180 | + async function handleCancelDispatchCustomer(record: Recordable) { | |
| 181 | + console.log('record', record); | |
| 182 | + await cancelDispatchCustomer({ ...record, customerId: '' }); | |
| 183 | + handleSuccess(); | |
| 184 | + } | |
| 149 | 185 | |
| 150 | 186 | function handleDetail(record: Recordable) { |
| 151 | 187 | const { id, tbDeviceId } = record; |
| ... | ... | @@ -191,12 +227,16 @@ |
| 191 | 227 | goDeviceProfile, |
| 192 | 228 | handleSelect, |
| 193 | 229 | registerModal, |
| 194 | - handleReload, | |
| 195 | 230 | registerDetailDrawer, |
| 196 | 231 | DeviceTypeEnum, |
| 197 | 232 | DeviceState, |
| 198 | 233 | searchInfo, |
| 199 | 234 | organizationIdTreeRef, |
| 235 | + handleDispatchCustomer, | |
| 236 | + handleCancelDispatchCustomer, | |
| 237 | + registerCustomerModal, | |
| 238 | + authBtn, | |
| 239 | + role, | |
| 200 | 240 | }; |
| 201 | 241 | }, |
| 202 | 242 | }); | ... | ... |
| ... | ... | @@ -41,7 +41,7 @@ export const columns: BasicColumn[] = [ |
| 41 | 41 | customRender: ({ record }) => { |
| 42 | 42 | const status = record.readStatus; |
| 43 | 43 | const enable = status == 0 ? '未读' : status == 1 ? '已读' : '其他'; |
| 44 | - const color = enable == '未读' ? 'green' : enable == '已读' ? 'yellow' : 'red'; | |
| 44 | + const color = enable == '未读' ? 'yellow' : enable == '已读' ? 'green' : 'red'; | |
| 45 | 45 | const text = enable == '未读' ? '未读' : enable == '已读' ? '已读' : '其他'; |
| 46 | 46 | return h(Tag, { color }, () => text); |
| 47 | 47 | }, | ... | ... |
| ... | ... | @@ -90,7 +90,7 @@ |
| 90 | 90 | setModalProps({ confirmLoading: true }); |
| 91 | 91 | await SaveOrUpdateUserInfo(values, unref(isUpdate)); |
| 92 | 92 | closeModal(); |
| 93 | - emit('success', { isUpdate: unref(isUpdate), values: { ...values, id: rowId.value } }); | |
| 93 | + emit('success'); | |
| 94 | 94 | createMessage.success(unref(isUpdate) ? '编辑成功' : '新增成功'); |
| 95 | 95 | } finally { |
| 96 | 96 | setModalProps({ confirmLoading: false }); | ... | ... |
| ... | ... | @@ -88,7 +88,7 @@ |
| 88 | 88 | const { createMessage } = useMessage(); |
| 89 | 89 | let searchInfo = reactive<Recordable>({}); |
| 90 | 90 | const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); |
| 91 | - const [registerTable, { reload, updateTableDataRecord }] = useTable({ | |
| 91 | + const [registerTable, { reload }] = useTable({ | |
| 92 | 92 | title: '账号列表', |
| 93 | 93 | api: getAccountList, |
| 94 | 94 | rowKey: 'id', |
| ... | ... | @@ -131,14 +131,8 @@ |
| 131 | 131 | }); |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | - function handleSuccess({ isUpdate, values }) { | |
| 135 | - if (isUpdate) { | |
| 136 | - // 演示不刷新表格直接更新内部数据。 | |
| 137 | - // 注意:updateTableDataRecord要求表格的rowKey属性为string并且存在于每一行的record的keys中 | |
| 138 | - updateTableDataRecord(values.id, values); | |
| 139 | - } else { | |
| 140 | - reload(); | |
| 141 | - } | |
| 134 | + function handleSuccess() { | |
| 135 | + reload(); | |
| 142 | 136 | } |
| 143 | 137 | |
| 144 | 138 | function handleSelect(organization) { | ... | ... |