Procházet zdrojové kódy

Merge branch 'master' into camera

louhangfei před 2 roky
rodič
revize
2a1385e5ec

+ 33 - 42
src/api/camera/camera-overview.ts

@@ -1,65 +1,56 @@
 import { http } from '@/utils/http/axios';
 import { CameraIPItem, CameraShowItem, CameraRangeItem } from '@/views/cameras/overview/type';
 
+export type PaginationArrayData<T> = {
+  records: T[];
+  pageNumber: number;
+  pageSize: number;
+  totalPage: number;
+  totalRow: number;
+};
+
 export type CameraQueryParams = {
   /** 相机协议类型 */
   cameraType?: string;
   /** 设备ID */
-  deviceId?: string;
+  code?: string;
   /** 相机IP */
   ip?: string;
   /** 场景 */
-  sceneId?: string;
+  sceneCode?: string;
+  pageNumber?: number;
+  pageSize?: number;
 };
 
 export const getCameraList = (params: CameraQueryParams) => {
-  return http.request<CameraShowItem[]>(
-    {
-      url: '/cameraConfig/getCamera',
-      method: 'get',
-      params,
-    },
-    {
-      urlPrefix: '',
-    },
-  );
+  return http.request<PaginationArrayData<CameraShowItem>>({
+    url: '/cameraConfig/findCamera',
+    method: 'get',
+    params,
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+  });
 };
 
 export const addCameraItem = (data: CameraIPItem) => {
-  return http.request(
-    {
-      url: '/cameraConfig/saveCamera',
-      method: 'post',
-      data,
-    },
-    {
-      urlPrefix: '',
-    },
-  );
+  return http.request({
+    url: '/cameraConfig/saveCamera',
+    method: 'post',
+    data: data,
+  });
 };
 
 export const getCamerasByIPRange = (params: CameraRangeItem) => {
-  return http.request<CameraShowItem[]>(
-    {
-      url: '/cameraConfig/getCameraByIpSegment',
-      method: 'get',
-      params,
-    },
-    {
-      urlPrefix: '',
-    },
-  );
+  return http.request<CameraShowItem[]>({
+    url: '/cameraConfig/getCameraByIpSegment',
+    method: 'get',
+    params,
+  });
 };
 
 export const updateCameraItem = (data: Partial<CameraIPItem>) => {
-  return http.request(
-    {
-      url: '/cameraConfig/updateCamera',
-      method: 'put',
-      data,
-    },
-    {
-      urlPrefix: '',
-    },
-  );
+  return http.request({
+    url: '/cameraConfig/updateCamera',
+    method: 'put',
+    data,
+  });
 };

+ 51 - 23
src/api/scene/scene.ts

@@ -1,5 +1,25 @@
 import { http } from '@/utils/http/axios';
 
+/** 场景标签信息 */
+export type SceneLabelOrModuleItem = {
+  /** 标签id */
+  id: number;
+  /** 标签代码 */
+  code: string;
+  /** 创建时间 */
+  createdAt: string;
+  /** 0-未删除,大于0-已删除 */
+  isDeleted: number;
+  /** 标签名称 */
+  name: string;
+  /** 说明 */
+  remark: string;
+  /** 状态: 0-正常,1-不正常 */
+  status: number;
+  /** 更新时间 */
+  updatedAt: string;
+};
+
 /** 工位信息 */
 export type WorkSpaceInfoItem = {
   /** 工位id */
@@ -20,6 +40,10 @@ export type WorkSpaceInfoItem = {
   updatedAt: string;
   /** 	0-未删除,大于0-已删除 */
   isDeleted: number;
+  /** 工位负责人 */
+  principal: string;
+  /** 排序序号 */
+  serial: number;
 };
 
 /** 工厂信息 */
@@ -45,7 +69,15 @@ export type WorkShopInfoItem = {
   /** 	0-未删除,大于0-已删除 */
   isDeleted: number;
   /** 下属工位列表 */
-  workspaceInfoList: WorkSpaceInfoItem[];
+  children: WorkSpaceInfoItem[];
+  /** 场景标签 */
+  labelName: string;
+  /** 场景标签id */
+  sceneLabelId: number;
+  /** 排序序号 */
+  serial: number;
+  /** 车间模板 */
+  workshopModule: SceneLabelOrModuleItem;
 };
 
 /** 公司信息 */
@@ -66,24 +98,25 @@ export type CompanyInfoItem = {
   createdAt: string;
   /** 更新时间 */
   updatedAt: string;
+  /** 排序序号 */
+  serial: number;
   /** 	0-未删除,大于0-已删除 */
   isDeleted: number;
   /** 下属工厂列表 */
-  workshopInfoList: WorkShopInfoItem[];
+  children: WorkShopInfoItem[];
+  /** 场景标签列表 */
+  labelList: SceneLabelOrModuleItem[];
+  /** 场景模板列表 */
+  moduleList: SceneLabelOrModuleItem[];
 };
 
 /** 获取公司-工厂-工位数据 */
 export const getShopSpaceList = () => {
-  return http.request<CompanyInfoItem[]>(
-    {
-      url: '/api/company/getCompanyShopSpaceList',
-      method: 'get',
-      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
-    },
-    {
-      urlPrefix: 'temp',
-    },
-  );
+  return http.request<CompanyInfoItem[]>({
+    url: '/scene/getList',
+    method: 'get',
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+  });
 };
 
 interface LayoutResp {
@@ -164,15 +197,10 @@ export type CameraItem = {
 export type WorkSpaceCameraRelative = WorkSpaceInfoItem & { cameraList: CameraItem[] };
 
 export const getCamerasByWorkSpace = (params: { workshopId: number }) => {
-  return http.request<WorkSpaceCameraRelative[]>(
-    {
-      url: '/api/workshop/getWorkspaceCameraList',
-      method: 'get',
-      params,
-      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
-    },
-    {
-      urlPrefix: 'temp',
-    },
-  );
+  return http.request<WorkSpaceCameraRelative[]>({
+    url: '/api/workshop/getWorkspaceCameraList',
+    method: 'get',
+    params,
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+  });
 };

+ 0 - 2
src/components/Table/src/hooks/useDataSource.ts

@@ -49,8 +49,6 @@ export function useDataSource(
   });
 
   async function fetch(opt?: {}, isRestReload?) {
-    console.log('fetch====');
-
     try {
       setLoading(true);
       const { request, pagination }: any = unref(propsRef);

+ 0 - 1
src/components/Table/src/types/table.ts

@@ -45,7 +45,6 @@ export interface TableSetting {
   fullscreen?: boolean;
   striped?: boolean;
   query?: boolean;
-  order?: boolean;
 }
 
 export interface BasicTableProps {

+ 43 - 55
src/hooks/useSceneInfos.ts

@@ -1,79 +1,60 @@
 import { computed, ref } from 'vue';
-import {
-  CompanyInfoItem,
-  WorkShopInfoItem,
-  WorkSpaceInfoItem,
-  getShopSpaceList,
-  getCamerasByWorkSpace,
-} from '@/api/scene/scene';
-import { cloneDeep } from 'lodash-es';
+import { CompanyInfoItem, getShopSpaceList, getCamerasByWorkSpace } from '@/api/scene/scene';
 
-type ElTreeItem = Partial<CompanyInfoItem | WorkShopInfoItem | WorkSpaceInfoItem> & {
+type ElTreeItem = {
   value: any;
   label: string;
   children?: ElTreeItem[];
 };
 
+type TreeProps = {
+  /** level:1-数据读取至公司 2-数据读取至工厂 3-数据读取至工位 */
+  level: number;
+  labelKey: string;
+  valueKey: string;
+  disabled?: boolean;
+};
+
 export function useSceneInfos() {
   const scenesInfos = ref<CompanyInfoItem[]>([]);
   const scenesTree = ref<ElTreeItem[]>([]);
-  /** level:1-数据读取至公司 2-数据读取至工厂 3-数据读取至工位 */
-  const level = ref(1);
-
-  const getSpaceItems = (spaces: WorkSpaceInfoItem[]): ElTreeItem[] => {
-    return spaces.map((space) => {
-      return {
-        ...space,
-        value: space.code,
-        label: space.name,
-        disabled: false,
-      };
-    });
-  };
 
   const flattenedWorkshops = computed(() => {
-    return scenesInfos.value.reduce((total, next) => [...total, ...next.workshopInfoList], []);
+    return scenesInfos.value.reduce((total, next) => [...total, ...next.children], []);
   });
 
-  const getShopItems = (shops: WorkShopInfoItem[]): ElTreeItem[] => {
-    return shops.map((shop) => {
-      const temp: any = cloneDeep(shop);
-      delete temp.workspaceInfoList;
-      const shopItem: ElTreeItem = {
-        ...temp,
-        value: temp.code,
-        label: shop.name,
-        disabled: level.value > 2 ? true : false,
-      };
-      if (level.value >= 3 && shop.workspaceInfoList && shop.workspaceInfoList.length > 0) {
-        shopItem.children = getSpaceItems(shop.workspaceInfoList);
+  const flattendWorkspaces = computed(() => {
+    return scenesInfos.value.reduce((total, next) => {
+      let newArr: any[] = [];
+      if (next.children && next.children.length) {
+        newArr = next.children.reduce(
+          (subTotal, subNext) => [...subTotal, ...subNext.children],
+          [],
+        );
       }
-      return shopItem;
-    });
-  };
+      return [...total, ...newArr];
+    }, []);
+  });
 
-  const calculateTreeData = (infos: CompanyInfoItem[]): ElTreeItem[] => {
-    return infos.map((company) => {
-      const temp: any = cloneDeep(company);
-      delete temp.workshopInfoList;
-      const companyItem: ElTreeItem = {
-        ...temp,
-        value: temp.code,
-        label: company.name,
-        disabled: level.value > 1 ? true : false,
+  const calculateTreeData = (infos: any[], treeProps: TreeProps, level: number): ElTreeItem[] => {
+    return infos.map((data) => {
+      return {
+        value: data[treeProps.valueKey],
+        label: data[treeProps.labelKey],
+        children:
+          data.children && data.children.length && treeProps.level > level
+            ? calculateTreeData(data.children, treeProps, level + 1)
+            : [],
+        disabled: treeProps.disabled && level < treeProps.level,
       };
-      if (level.value >= 2 && company.workshopInfoList && company.workshopInfoList.length > 0) {
-        companyItem.children = getShopItems(company.workshopInfoList);
-      }
-      return companyItem;
     });
   };
 
-  const getScenesTree = (_level: number) => {
-    level.value = _level;
+  const getScenesTree = (treeProps: TreeProps) => {
     getShopSpaceList().then((res) => {
       scenesInfos.value = res;
-      scenesTree.value = calculateTreeData(res);
+      scenesTree.value = calculateTreeData(res, treeProps, 1);
+      console.log(flattendWorkspaces.value);
     });
   };
 
@@ -83,7 +64,14 @@ export function useSceneInfos() {
     });
   };
 
-  return { scenesInfos, scenesTree, flattenedWorkshops, getScenesTree, getCameraList };
+  return {
+    scenesInfos,
+    scenesTree,
+    flattenedWorkshops,
+    flattendWorkspaces,
+    getScenesTree,
+    getCameraList,
+  };
 }
 
 export default useSceneInfos;

+ 14 - 2
src/views/cameras/overview/CamerasOverview.vue

@@ -7,7 +7,7 @@
         :data-source="cameraItems"
         :row-key="(row) => row.code"
         :action-column="actionColumn"
-        :pagination="false"
+        :pagination="{ total: total, pageSize: size, hideOnSinglePage: !cameraItems.length }"
         :loading="loading"
         :tableSetting="{
           size: false,
@@ -19,6 +19,8 @@
         :striped="true"
         ref="tableRef"
         @order-change="orderByItem"
+        @page-num-change="handlePageNumChange"
+        @page-size-change="handlePageSizeChange"
       >
         <template #tableTitle>
           <el-button type="primary" :icon="Plus" @click="showAddPopover = true">添加</el-button>
@@ -54,7 +56,7 @@
   import { CameraIPItem } from './type';
 
   const cameraOverview = useCameraOverview();
-  const { cameraItems, loading } = storeToRefs(cameraOverview);
+  const { cameraItems, loading, total, page, size } = storeToRefs(cameraOverview);
   const { getCameraItems } = cameraOverview;
 
   // 添加弹窗相关
@@ -100,6 +102,16 @@
   // 列排序操作
   const orderByItem = () => {};
 
+  const handlePageNumChange = (pageNum) => {
+    page.value = pageNum;
+    getCameraItems();
+  };
+
+  const handlePageSizeChange = (pageSize) => {
+    size.value = pageSize;
+    getCameraItems();
+  };
+
   const handlePreview = () => {};
 
   const handleDelete = () => {};

+ 21 - 1
src/views/cameras/overview/components/AddCameraByIP.vue

@@ -36,6 +36,16 @@
               :value="protocal.value"
             />
           </el-select>
+          <el-tree-select
+            v-if="item.type === 'tree-select'"
+            v-model="cameraIPData[item.prop]"
+            :data="scenesTree"
+            :render-after-expand="false"
+            :default-expand-all="true"
+            check-strictly
+            :placeholder="item.placeholder"
+            style="width: 200px"
+          />
         </el-form-item>
       </el-form>
     </div>
@@ -50,11 +60,16 @@
   import { computed, onBeforeMount, ref } from 'vue';
   import { CameraIPItem } from '../type';
   import { cameraIPAddForm } from '../constant';
+  import useSceneInfos from '@/hooks/useSceneInfos';
+  import { cloneDeep } from 'lodash-es';
 
   const props = defineProps<{ formData?: CameraIPItem | null }>();
 
   const emits = defineEmits(['cancel-execute', 'confirm-execute']);
 
+  const sceneInfos = useSceneInfos();
+  const { scenesTree, flattendWorkspaces, getScenesTree } = sceneInfos;
+
   const cameraIPData = ref<CameraIPItem>({} as CameraIPItem);
 
   const rules = computed(() => {
@@ -72,10 +87,15 @@
   };
 
   const handleConfirm = () => {
-    emits('confirm-execute', cameraIPData.value);
+    const copyData = cloneDeep(cameraIPData.value);
+    copyData.workspaceId = flattendWorkspaces.value.find(
+      (item) => item.code === cameraIPData.value.workspaceId,
+    ).id;
+    emits('confirm-execute', copyData);
   };
 
   onBeforeMount(() => {
+    getScenesTree({ level: 3, valueKey: 'code', labelKey: 'name', disabled: true });
     if (props.formData) {
       cameraIPData.value = props.formData;
     }

+ 21 - 11
src/views/cameras/overview/components/ConditionQuery.vue

@@ -30,14 +30,15 @@
       </div>
       <div>
         <span>场景:</span>
-        <el-select v-model="queryWorkShop" placeholder="请选择场景" class="protocal-select">
-          <el-option
-            v-for="item in protocalTypeSelect"
-            :key="item.value"
-            :label="item.label"
-            :value="item.value"
-          />
-        </el-select>
+        <el-tree-select
+          v-model="queryWorkSpace"
+          :data="scenesTree"
+          :render-after-expand="false"
+          :default-expand-all="true"
+          check-strictly
+          placeholder="请选择场景"
+          class="protocal-select"
+        />
       </div>
     </el-space>
     <div class="flex-1 flex justify-end">
@@ -48,12 +49,17 @@
 </template>
 
 <script setup lang="ts">
-  import { storeToRefs } from 'pinia';
+  import { onMounted } from 'vue';
   import { queryTypeSelect, protocalTypeSelect } from '../constant';
   import useCameraOverview from '../stores/useCameraOverview';
+  import useSceneInfos from '@/hooks/useSceneInfos';
+  import { storeToRefs } from 'pinia';
+
+  const sceneInfos = useSceneInfos();
+  const { scenesTree, getScenesTree } = sceneInfos;
 
   const cameraOverview = useCameraOverview();
-  const { queryType, queryTypeContent, queryCameraType, queryWorkShop } =
+  const { queryType, queryTypeContent, queryCameraType, queryWorkSpace } =
     storeToRefs(cameraOverview);
   const { getCameraItems } = cameraOverview;
 
@@ -62,8 +68,12 @@
     queryType.value = '';
     queryTypeContent.value = '';
     queryCameraType.value = '';
-    queryWorkShop.value = '';
+    queryWorkSpace.value = '';
   };
+
+  onMounted(() => {
+    getScenesTree({ level: 3, valueKey: 'code', labelKey: 'name' });
+  });
 </script>
 
 <style scoped>

+ 4 - 4
src/views/cameras/overview/constant.ts

@@ -43,7 +43,7 @@ type CameraAddFormItem = {
   label: string;
   prop: string;
   placeholder: string;
-  type: 'input' | 'select';
+  type: 'input' | 'select' | 'tree-select';
   option?: { value: any; label: any }[];
   required: boolean;
   rule?: any[];
@@ -86,7 +86,7 @@ export const cameraIPAddForm: CameraAddFormItem[] = [
   },
   {
     label: '用户名:',
-    prop: 'userName',
+    prop: 'username',
     placeholder: '请输入用户名',
     type: 'input',
     required: true,
@@ -94,9 +94,9 @@ export const cameraIPAddForm: CameraAddFormItem[] = [
   },
   {
     label: '场景:',
-    prop: 'workshopId',
+    prop: 'workspaceId',
     placeholder: '请输入场景名称',
-    type: 'input',
+    type: 'tree-select',
     required: true,
     rule: [{ required: true, message: '请输入场景名称', trigger: 'blur' }],
   },

+ 1 - 1
src/views/cameras/overview/overviewColumns.ts

@@ -60,7 +60,7 @@ export const columns: BasicColumn[] = [
   {
     label: '工位场景',
     prop: 'workspaceName',
-    minWidth: 80,
+    minWidth: 140,
   },
   {
     label: '联网状态',

+ 17 - 7
src/views/cameras/overview/stores/useCameraOverview.ts

@@ -13,13 +13,19 @@ export const useCameraOverview = defineStore('camera-overview', () => {
   const queryType = ref('');
   const queryTypeContent = ref('');
   const queryCameraType = ref('');
-  const queryWorkShop = ref('');
+  const queryWorkSpace = ref('');
+  const total = ref(0);
+  const page = ref(1);
+  const size = ref(10);
 
   const cameraItems = ref<CameraShowItem[]>([]);
 
   // 条件查询事件
   const conditionSearch = () => {
-    const params: CameraQueryParams = {};
+    const params: CameraQueryParams = {
+      pageNumber: page.value,
+      pageSize: size.value,
+    };
     if (queryType.value) {
       switch (queryType.value) {
         case 'cameraIp':
@@ -27,15 +33,15 @@ export const useCameraOverview = defineStore('camera-overview', () => {
           break;
 
         case 'name':
-          params.deviceId = queryTypeContent.value;
+          params.code = queryTypeContent.value;
           break;
       }
     }
     if (queryCameraType.value) {
       params.cameraType = queryCameraType.value;
     }
-    if (queryWorkShop.value) {
-      params.sceneId = queryWorkShop.value;
+    if (queryWorkSpace.value) {
+      params.sceneCode = queryWorkSpace.value;
     }
     return getCameraList(params).then((res) => {
       return res;
@@ -45,7 +51,8 @@ export const useCameraOverview = defineStore('camera-overview', () => {
   const { loading, run: getCameraItems } = useRequest(conditionSearch, {
     manual: true,
     onSuccess: (res) => {
-      cameraItems.value = res;
+      cameraItems.value = [...res.records];
+      total.value = res.totalRow;
     },
   });
 
@@ -65,9 +72,12 @@ export const useCameraOverview = defineStore('camera-overview', () => {
     queryType,
     queryTypeContent,
     queryCameraType,
-    queryWorkShop,
+    queryWorkSpace,
     cameraItems,
     loading,
+    total,
+    size,
+    page,
     getCameraItems,
     addCamera,
     editCamera,

+ 1 - 1
src/views/cameras/overview/type.ts

@@ -18,7 +18,7 @@ export interface CameraIPItem {
   /** id */
   id?: number;
   /** 用户名 */
-  userName?: string;
+  username?: string;
   /** 密码 */
   password?: string;
 }

+ 17 - 22
src/views/map-config/mini-map/MiniMapConfig.vue

@@ -10,6 +10,7 @@
             :data="scenesTree"
             accordion
             :render-after-expand="false"
+            :default-expand-all="true"
             :teleported="false"
             placeholder="请选择相关场景"
             @change="changeShop"
@@ -81,27 +82,21 @@
         </el-scrollbar>
       </div>
       <div class="draw-container">
-        <div style="display: flex; margin-bottom: 20px">
-          <el-upload
-            class="avatar-uploader flex justify-center items-center"
-            action="/temp/api/layout/uploadPicture"
-            :show-file-list="false"
-            :on-success="handleAvatarSuccess"
-            :with-credentials="true"
-            name="file"
-            :data="{ workshopId: selectedShopDetail?.id }"
-          >
-            <el-button style="font-size: 12px">+ 更换/上传背景图片</el-button>
-          </el-upload>
-
-          <el-button
-            @click="handleSave"
-            style="margin-left: 40px"
-            type="primary"
-            :disabled="!selectedShopCode"
-            >保存布局</el-button
-          >
+        <div style="overflow: auto">
+          <canvas width="400" height="400" id="mapEditCanvas"></canvas>
         </div>
+        <el-upload
+          v-if="!hasBg"
+          class="upload-icon flex justify-center items-center"
+          action="/temp/api/layout/uploadPicture"
+          :show-file-list="false"
+          :on-success="handleAvatarSuccess"
+          :with-credentials="true"
+          name="file"
+          :data="{ workshopId: selectedShopCode }"
+        >
+          <img src="~@/assets/images/img-upload.png" />
+        </el-upload>
         <div>
           <div style="height: 20px; margin-bottom: 10px">
             <div v-if="selectedCamera">
@@ -113,7 +108,6 @@
             </div>
           </div>
         </div>
-        -->
         <div style="overflow: auto">
           <canvas width="400" height="400" id="mapEditCanvas"></canvas>
         </div>
@@ -155,6 +149,7 @@
   import { createSelectedPositionHash, getFavPositionByCamera } from './MapBase/utils';
   import SelectedCameraToolbar from './components/SelectedCameraToolbar.vue';
   import CameraPreview from './MapBase/CameraPreview.vue';
+  import { Search, Refresh } from '@element-plus/icons-vue';
 
   const miniMap = useMiniMap();
   const globSetting = useGlobSetting();
@@ -261,7 +256,7 @@
   };
 
   onMounted(() => {
-    getScenesTree(2);
+    getScenesTree({ level: 2, valueKey: 'code', labelKey: 'name', disabled: true });
     if (selectedShopCode.value) {
       getShopContent(selectedShopCode.value);
     }