Commit bdeac9846c3e3a8d010cf2b1aeb253fba2482ee0

Authored by sqy
1 parent 6000cf9a

'feat:设备分配客户,oem按钮调整,地图铆钉不显示,账号问题'

@@ -136,3 +136,35 @@ export const saveDeviceToken = (data) => { @@ -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 +};
@@ -12,3 +12,10 @@ export function isAdmin(role: string) { @@ -12,3 +12,10 @@ export function isAdmin(role: string) {
12 return false; 12 return false;
13 } 13 }
14 } 14 }
  15 +// 按钮级权限控制,只针对客户
  16 +export function authBtn(role: string): boolean {
  17 + if (role === RoleEnum.CUSTOMER_USER) {
  18 + return false;
  19 + }
  20 + return true;
  21 +}
@@ -329,6 +329,7 @@ @@ -329,6 +329,7 @@
329 data: dataArray.filter((item1) => item1[2] === item), 329 data: dataArray.filter((item1) => item1[2] === item),
330 }; 330 };
331 }); 331 });
  332 + console.log(dataArray);
332 // 设置数据; 333 // 设置数据;
333 setOptions({ 334 setOptions({
334 tooltip: { 335 tooltip: {
1 import { formatToDateTime } from '/@/utils/dateUtil'; 1 import { formatToDateTime } from '/@/utils/dateUtil';
2 import { FormSchema } from '/@/components/Form'; 2 import { FormSchema } from '/@/components/Form';
3 import { BasicColumn } from '/@/components/Table'; 3 import { BasicColumn } from '/@/components/Table';
4 -  
5 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; 4 import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
6 - 5 +import { getCustomerList } from '/@/api/device/deviceManager';
7 export const columns: BasicColumn[] = [ 6 export const columns: BasicColumn[] = [
8 { 7 {
9 title: '设备名称', 8 title: '设备名称',
@@ -287,3 +286,19 @@ export const statusType = (type: string): string => { @@ -287,3 +286,19 @@ export const statusType = (type: string): string => {
287 return '激活未确认'; 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 +];
@@ -24,7 +24,6 @@ export const columns: BasicColumn[] = [ @@ -24,7 +24,6 @@ export const columns: BasicColumn[] = [
24 slots: { customRender: 'deviceProfile' }, 24 slots: { customRender: 'deviceProfile' },
25 ellipsis: true, 25 ellipsis: true,
26 }, 26 },
27 -  
28 { 27 {
29 title: '所属组织', 28 title: '所属组织',
30 dataIndex: 'organizationDTO.name', 29 dataIndex: 'organizationDTO.name',
  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,7 +11,12 @@
11 :customRequest="customUpload" 11 :customRequest="customUpload"
12 :before-upload="beforeUpload" 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 <div v-else> 20 <div v-else>
16 <PlusOutlined /> 21 <PlusOutlined />
17 <div class="ant-upload-text">图片上传</div> 22 <div class="ant-upload-text">图片上传</div>
@@ -76,7 +81,6 @@ @@ -76,7 +81,6 @@
76 [Divider.name]: Divider, 81 [Divider.name]: Divider,
77 Upload, 82 Upload,
78 EnvironmentTwoTone, 83 EnvironmentTwoTone,
79 - // LoadingOutlined,  
80 PlusOutlined, 84 PlusOutlined,
81 Modal, 85 Modal,
82 [Form.name]: Form, 86 [Form.name]: Form,
@@ -175,7 +179,8 @@ @@ -175,7 +179,8 @@
175 if (!wrapEl) return; 179 if (!wrapEl) return;
176 let preMarker = null; 180 let preMarker = null;
177 const map = new BMap.Map(wrapEl); 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 const point = new BMap.Point(Number(longitude), Number(latitude)); 184 const point = new BMap.Point(Number(longitude), Number(latitude));
180 let marker = new BMap.Marker(point, { icon: myIcon }); 185 let marker = new BMap.Marker(point, { icon: myIcon });
181 if (marker) { 186 if (marker) {
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 /> 8 />
9 <BasicTable @register="registerTable" class="w-5/6 xl:w-4/5"> 9 <BasicTable @register="registerTable" class="w-5/6 xl:w-4/5">
10 <template #toolbar> 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 </template> 12 </template>
13 <template #deviceProfile="{ record }"> 13 <template #deviceProfile="{ record }">
14 <a-button type="link" class="ml-2" @click="goDeviceProfile"> 14 <a-button type="link" class="ml-2" @click="goDeviceProfile">
@@ -50,6 +50,23 @@ @@ -50,6 +50,23 @@
50 <template #action="{ record }"> 50 <template #action="{ record }">
51 <TableAction 51 <TableAction
52 :actions="[ 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 label: '详情', 71 label: '详情',
55 icon: 'ant-design:eye-outlined', 72 icon: 'ant-design:eye-outlined',
@@ -58,11 +75,13 @@ @@ -58,11 +75,13 @@
58 { 75 {
59 label: '编辑', 76 label: '编辑',
60 icon: 'clarity:note-edit-line', 77 icon: 'clarity:note-edit-line',
  78 + ifShow: authBtn(role),
61 onClick: handleEdit.bind(null, record), 79 onClick: handleEdit.bind(null, record),
62 }, 80 },
63 { 81 {
64 label: '删除', 82 label: '删除',
65 icon: 'ant-design:delete-outlined', 83 icon: 'ant-design:delete-outlined',
  84 + ifShow: authBtn(role),
66 color: 'error', 85 color: 'error',
67 popConfirm: { 86 popConfirm: {
68 title: '是否确认删除', 87 title: '是否确认删除',
@@ -74,7 +93,8 @@ @@ -74,7 +93,8 @@
74 </template> 93 </template>
75 </BasicTable> 94 </BasicTable>
76 <DeviceDetailDrawer @register="registerDetailDrawer" /> 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 </PageWrapper> 98 </PageWrapper>
79 </div> 99 </div>
80 </template> 100 </template>
@@ -85,7 +105,7 @@ @@ -85,7 +105,7 @@
85 import { columns, searchFormSchema } from './config/device.data'; 105 import { columns, searchFormSchema } from './config/device.data';
86 import { Tag } from 'ant-design-vue'; 106 import { Tag } from 'ant-design-vue';
87 import { useMessage } from '/@/hooks/web/useMessage'; 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 import { PageEnum } from '/@/enums/pageEnum'; 109 import { PageEnum } from '/@/enums/pageEnum';
90 import { useGo } from '/@/hooks/web/usePage'; 110 import { useGo } from '/@/hooks/web/usePage';
91 import { PageWrapper } from '/@/components/Page'; 111 import { PageWrapper } from '/@/components/Page';
@@ -95,7 +115,11 @@ @@ -95,7 +115,11 @@
95 import DeviceModal from './cpns/modal/DeviceModal.vue'; 115 import DeviceModal from './cpns/modal/DeviceModal.vue';
96 import { useDrawer } from '/@/components/Drawer'; 116 import { useDrawer } from '/@/components/Drawer';
97 import DeviceDetailDrawer from './cpns/modal/DeviceDetailDrawer.vue'; 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 export default defineComponent({ 123 export default defineComponent({
100 name: 'DeviceManagement', 124 name: 'DeviceManagement',
101 components: { 125 components: {
@@ -106,6 +130,7 @@ @@ -106,6 +130,7 @@
106 Tag, 130 Tag,
107 DeviceModal, 131 DeviceModal,
108 DeviceDetailDrawer, 132 DeviceDetailDrawer,
  133 + CustomerModal,
109 }, 134 },
110 setup(_) { 135 setup(_) {
111 const { createMessage } = useMessage(); 136 const { createMessage } = useMessage();
@@ -114,6 +139,7 @@ @@ -114,6 +139,7 @@
114 const searchInfo = reactive<Recordable>({}); 139 const searchInfo = reactive<Recordable>({});
115 const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); 140 const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
116 const [registerModal, { openModal }] = useModal(); 141 const [registerModal, { openModal }] = useModal();
  142 + const [registerCustomerModal, { openModal: openCustomerModal }] = useModal();
117 const [registerDetailDrawer, { openDrawer }] = useDrawer(); 143 const [registerDetailDrawer, { openDrawer }] = useDrawer();
118 const [registerTable, { reload }] = useTable({ 144 const [registerTable, { reload }] = useTable({
119 title: '设备列表', 145 title: '设备列表',
@@ -130,22 +156,32 @@ @@ -130,22 +156,32 @@
130 showIndexColumn: false, 156 showIndexColumn: false,
131 searchInfo: searchInfo, 157 searchInfo: searchInfo,
132 actionColumn: { 158 actionColumn: {
133 - width: 200, 159 + width: 250,
134 title: '操作', 160 title: '操作',
135 dataIndex: 'action', 161 dataIndex: 'action',
136 slots: { customRender: 'action' }, 162 slots: { customRender: 'action' },
137 fixed: 'right', 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 function handleCreate() { 170 function handleCreate() {
145 openModal(true, { 171 openModal(true, {
146 isUpdate: false, 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 function handleDetail(record: Recordable) { 186 function handleDetail(record: Recordable) {
151 const { id, tbDeviceId } = record; 187 const { id, tbDeviceId } = record;
@@ -191,12 +227,16 @@ @@ -191,12 +227,16 @@
191 goDeviceProfile, 227 goDeviceProfile,
192 handleSelect, 228 handleSelect,
193 registerModal, 229 registerModal,
194 - handleReload,  
195 registerDetailDrawer, 230 registerDetailDrawer,
196 DeviceTypeEnum, 231 DeviceTypeEnum,
197 DeviceState, 232 DeviceState,
198 searchInfo, 233 searchInfo,
199 organizationIdTreeRef, 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,7 +41,7 @@ export const columns: BasicColumn[] = [
41 customRender: ({ record }) => { 41 customRender: ({ record }) => {
42 const status = record.readStatus; 42 const status = record.readStatus;
43 const enable = status == 0 ? '未读' : status == 1 ? '已读' : '其他'; 43 const enable = status == 0 ? '未读' : status == 1 ? '已读' : '其他';
44 - const color = enable == '未读' ? 'green' : enable == '已读' ? 'yellow' : 'red'; 44 + const color = enable == '未读' ? 'yellow' : enable == '已读' ? 'green' : 'red';
45 const text = enable == '未读' ? '未读' : enable == '已读' ? '已读' : '其他'; 45 const text = enable == '未读' ? '未读' : enable == '已读' ? '已读' : '其他';
46 return h(Tag, { color }, () => text); 46 return h(Tag, { color }, () => text);
47 }, 47 },
@@ -21,6 +21,7 @@ @@ -21,6 +21,7 @@
21 name: 'AccountDetail', 21 name: 'AccountDetail',
22 components: { PageWrapper, Description }, 22 components: { PageWrapper, Description },
23 setup() { 23 setup() {
  24 + console.log(123);
24 const route = useRoute(); 25 const route = useRoute();
25 const go = useGo(); 26 const go = useGo();
26 const { setTitle, close } = useTabs(); 27 const { setTitle, close } = useTabs();
@@ -90,7 +90,7 @@ @@ -90,7 +90,7 @@
90 setModalProps({ confirmLoading: true }); 90 setModalProps({ confirmLoading: true });
91 await SaveOrUpdateUserInfo(values, unref(isUpdate)); 91 await SaveOrUpdateUserInfo(values, unref(isUpdate));
92 closeModal(); 92 closeModal();
93 - emit('success', { isUpdate: unref(isUpdate), values: { ...values, id: rowId.value } }); 93 + emit('success');
94 createMessage.success(unref(isUpdate) ? '编辑成功' : '新增成功'); 94 createMessage.success(unref(isUpdate) ? '编辑成功' : '新增成功');
95 } finally { 95 } finally {
96 setModalProps({ confirmLoading: false }); 96 setModalProps({ confirmLoading: false });
@@ -88,7 +88,7 @@ @@ -88,7 +88,7 @@
88 const { createMessage } = useMessage(); 88 const { createMessage } = useMessage();
89 let searchInfo = reactive<Recordable>({}); 89 let searchInfo = reactive<Recordable>({});
90 const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); 90 const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo);
91 - const [registerTable, { reload, updateTableDataRecord }] = useTable({ 91 + const [registerTable, { reload }] = useTable({
92 title: '账号列表', 92 title: '账号列表',
93 api: getAccountList, 93 api: getAccountList,
94 rowKey: 'id', 94 rowKey: 'id',
@@ -131,14 +131,8 @@ @@ -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 function handleSelect(organization) { 138 function handleSelect(organization) {
@@ -79,7 +79,7 @@ @@ -79,7 +79,7 @@
79 @click="handleUpdateInfo" 79 @click="handleUpdateInfo"
80 size="large" 80 size="large"
81 type="primary" 81 type="primary"
82 - style="margin-top: 20px; background-color: #2950f7; border-radius: 5px" 82 + style="margin-top: 20px; border-radius: 5px"
83 >保存信息</a-button 83 >保存信息</a-button
84 > 84 >
85 </div> 85 </div>
@@ -79,7 +79,7 @@ @@ -79,7 +79,7 @@
79 @click="handleUpdateInfo" 79 @click="handleUpdateInfo"
80 size="large" 80 size="large"
81 type="primary" 81 type="primary"
82 - style="margin-top: 20px; background-color: #2950f7; border-radius: 5px" 82 + style="margin-top: 20px; border-radius: 5px"
83 >保存信息</a-button 83 >保存信息</a-button
84 > 84 >
85 </div> 85 </div>
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 @click="handleUpdateInfo" 32 @click="handleUpdateInfo"
33 size="large" 33 size="large"
34 type="primary" 34 type="primary"
35 - style="margin-top: 20px; background-color: #2950f7; border-radius: 5px" 35 + style="margin-top: 20px; border-radius: 5px"
36 >更新基本信息</a-button 36 >更新基本信息</a-button
37 > 37 >
38 </div> 38 </div>
@@ -81,6 +81,7 @@ @@ -81,6 +81,7 @@
81 record, 81 record,
82 isUpdate: true, 82 isUpdate: true,
83 }); 83 });
  84 + console.log(record);
84 } 85 }
85 86
86 async function handleDelete(record: Recordable) { 87 async function handleDelete(record: Recordable) {