فهرست منبع

Merge branch 'wyf-dev' into 'all'

场景管理对公司一级添加头像功能

See merge request skyeye/skyeye_frontend/skyeye-admin!185
楼航飞 1 سال پیش
والد
کامیت
534ec688d1

+ 2 - 0
src/api/scene/scene.ts

@@ -108,6 +108,8 @@ export type CompanyInfoItem = {
   labelList: SceneLabelOrModuleItem[];
   /** 场景模板列表 */
   moduleList: SceneLabelOrModuleItem[];
+  // 模板列表信息
+  labelModuleList: { sceneLabel: SceneLabelOrModuleItem; sceneModule: SceneLabelOrModuleItem }[];
 };
 
 /** 获取公司-工厂-工位数据 */

+ 2 - 1
src/api/scene/sceneOperate.ts

@@ -17,7 +17,8 @@ export interface ComAddDatas {
   parent?: null | ComAddDatas;
   longitude?: number; //经度
   latitude?: number; //纬度
-  regionCode: string;
+  regionCode?: string;
+  thumbnail?: string;
 }
 
 /**

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 38 - 0
src/assets/images/MobileConfigMap/life.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 37 - 0
src/assets/images/MobileConfigMap/logistics.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 34 - 0
src/assets/images/MobileConfigMap/production-safe.svg


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 36 - 0
src/assets/images/MobileConfigMap/safe-env.svg


+ 45 - 19
src/views/page-config/ConfigEdit.vue

@@ -20,23 +20,31 @@
           </el-select>
         </div>
         <div v-if="selectedCompany" style="display: flex">
-          <div class="label-workshop">选择标签:</div>
-          <div>
-            <el-radio-group
-              v-model="label"
-              :border="true"
-              style="display: flex"
-              @change="changeShop"
-            >
-              <el-radio-button
-                v-for="item in labelList"
-                :key="item.id"
-                :label="item.id!"
-                class="label-select"
-                >{{ item.name }}</el-radio-button
+          <div style="display: flex">
+            <div class="label-workshop" style="margin-left: 0px">选择标签:</div>
+            <div>
+              <el-radio-group
+                v-model="label"
+                :border="true"
+                style="display: flex"
+                @change="changeShop"
               >
-            </el-radio-group></div
-          >
+                <el-radio-button
+                  v-for="item in labelList"
+                  :key="item.id"
+                  :label="item.id!"
+                  class="label-select"
+                  >{{ item.name }}</el-radio-button
+                >
+              </el-radio-group></div
+            >
+          </div>
+          <!-- <div v-if="false" style="display: flex">
+            <div class="label-workshop" style="margin-left: 10px">是否开启移动端视角</div>
+            <div>
+              <el-switch v-model="isMobileView" style="margin-left: 10px" />
+            </div>
+          </div> -->
         </div>
         <div class="flex">
           <!-- <el-button @click="toJson">tojson</el-button> -->
@@ -96,7 +104,12 @@
       </div>
       <div ref="drawContainer" id="drawContainer" class="draw-container">
         <div id="shopEditContainer" v-moveable:1>
-          <MapContainer ref="mapContainerRef" @on-open="openConfig" />
+          <MapContainer
+            ref="mapContainerRef"
+            :is-mobile-view="isMobileView"
+            :module-code="labelMouduleCode"
+            @on-open="openConfig"
+          />
         </div>
         <el-upload
           v-if="!hasBg"
@@ -122,7 +135,7 @@
       placement="left"
     >
       <div
-        v-if="leftShow && activeShopId && activeShopId != -1"
+        v-if="leftShow && activeShopId && !isMobileView && activeShopId != -1"
         class="circle-rectangle"
         :class="{ 'shape-shadow': shadow }"
         @mouseover="shadowAdd"
@@ -135,6 +148,7 @@
     </el-tooltip>
 
     <ConfigDialog
+      v-if="!isMobileView"
       ref="configDrawer"
       @on-close="onClose"
       @transformer-change="transformChange"
@@ -154,7 +168,7 @@
   import ConfigDialog from './component/ConfigDrawer.vue';
   import ConfigFinish from './component/ConfigFinish.vue';
   import { storeToRefs } from 'pinia';
-  import { ElMessage, ElInput } from 'element-plus';
+  import { ElMessage, ElInput, ElSwitch } from 'element-plus';
   import { onBeforeUnmount, onMounted, ref, watch } from 'vue';
   import { WorkShopInfoItem } from '@/api/scene/scene';
   import { computed } from 'vue';
@@ -185,6 +199,9 @@
   // 是否已有背景图
   const hasBg = ref(false);
 
+  // 是否开启移动端视图
+  const isMobileView = ref(false);
+
   const handleBeforeUpload = (rawFile) => {
     if (!selectedCompany.value || !label.value) {
       ElMessage.error({
@@ -261,6 +278,15 @@
     addBg();
   };
 
+  const labelMouduleCode = computed(() => {
+    return (
+      scenesInfos.value
+        .find((item) => item.id === selectedCompany.value)
+        ?.labelModuleList.find((item) => item.sceneLabel.id === label.value)?.sceneModule.code ||
+      'default'
+    );
+  });
+
   const changeShop = () => {
     hasBg.value = false;
     resetMap();

+ 93 - 0
src/views/page-config/component/mapContainer/LabelItemMobile.vue

@@ -0,0 +1,93 @@
+<template>
+  <v-image ref="pointRef" :config="getIconConfig(curvImage)" />
+  <!-- <v-image :config="getCirConfig(props.shop.posType, cirImage)" />
+  <v-image ref="rectRef" :config="getRectCurConfig(props.shop.posType, rectImage)" /> -->
+  <v-rect :config="getRectConfig(props.shop)" />
+  <v-text :config="getTextConfig(props.shop)" />
+</template>
+
+<script setup lang="ts">
+  import { ref, onMounted, nextTick, watch } from 'vue';
+  import ProductionSafe from '@/assets/images/MobileConfigMap/production-safe.svg';
+  import SafeEnv from '@/assets/images/MobileConfigMap/safe-env.svg';
+  import Life from '@/assets/images/MobileConfigMap/life.svg';
+  import Logistics from '@/assets/images/MobileConfigMap/logistics.svg';
+  import Konva from 'konva';
+  import { MapWorkShopInfoItem } from '../../stores/useMapEditor';
+  import { getIconConfig, getRectConfig, getTextConfig } from './labelConfigMobile';
+
+  const props = defineProps<{ shop: MapWorkShopInfoItem; moduleCode: string }>();
+
+  const curvImage = ref<HTMLImageElement>(new Image());
+  // const rectImage = ref<HTMLImageElement>(new Image());
+  // const shineImage = ref<HTMLImageElement>(new Image());
+  // const cirImage = ref<HTMLImageElement>(new Image());
+  const rectRef = ref<Konva.Image>();
+  const pointRef = ref<Konva.Image>();
+
+  const nodeUpdateFilter = (node: Konva.Node) => {
+    node.cache();
+    // const rgba = getRGBANum(props.shop.bgColor);
+    // node.red(rgba[0]);
+    // node.green(rgba[1]);
+    // node.blue(rgba[2]);
+    // node.alpha(rgba[3]);
+  };
+
+  const IconMap = {
+    companyLife: Life,
+    companyProductionSafe: ProductionSafe,
+    companySafeEnv: SafeEnv,
+    companyLogistics: Logistics,
+    // 加入了一个默认code用于其他code都找不到的情况
+    default: ProductionSafe,
+  };
+
+  watch(
+    () => props.shop,
+    () => {
+      nextTick(() => {
+        nodeUpdateFilter(pointRef.value!.getNode());
+        nodeUpdateFilter(rectRef.value!.getNode());
+      });
+    },
+    { deep: true },
+  );
+
+  onMounted(() => {
+    const svgImg = new Image();
+    svgImg.onload = () => {
+      curvImage.value = svgImg;
+      nextTick(() => {
+        nodeUpdateFilter(pointRef.value?.getNode());
+      });
+    };
+    svgImg.src = IconMap[props.moduleCode];
+
+    // const rectImg = new Image();
+    // rectImg.onload = () => {
+    //   rectImage.value = rectImg;
+    //   nextTick(() => {
+    //     nodeUpdateFilter(rectRef.value?.getNode());
+    //   });
+    // };
+    // rectImg.src = rectBlock;
+
+    // const shineImg = new Image();
+    // shineImg.onload = () => {
+    //   shineImage.value = shineImg;
+    // };
+    // shineImg.src = shine;
+
+    // const cirImg = new Image();
+    // cirImg.onload = () => {
+    //   cirImage.value = cirImg;
+    // };
+    // cirImg.src = circle;
+
+    // rectRef.value?.getNode().filters([Konva.Filters.RGBA]);
+    // pointRef.value?.getNode().filters([Konva.Filters.RGBA]);
+  });
+</script>
+
+<style scoped></style>

+ 29 - 4
src/views/page-config/component/mapContainer/MapContainer.vue

@@ -14,7 +14,13 @@
           :config="getGroupConfig(item)"
           @dblclick="handleClick"
         >
-          <LabelItem :shop="item" />
+          <LabelItemMobile
+            v-if="isMobileView"
+            :shop="item"
+            :is-mobile-view="isMobileView"
+            :module-code="moduleCode"
+          />
+          <LabelItem v-else :shop="item" :is-mobile-view="isMobileView" />
         </v-group>
         <v-transformer ref="transformerRef" :config="transformerConfig" />
       </v-layer>
@@ -25,6 +31,7 @@
 <script setup lang="ts">
   import { computed, ref, watch, nextTick } from 'vue';
   import LabelItem from './LabelItem.vue';
+  import LabelItemMobile from './LabelItemMobile.vue';
   import { storeToRefs } from 'pinia';
   import useMapEditor, { MapWorkShopInfoItem } from '../../stores/useMapEditor';
   import Konva from 'konva';
@@ -32,6 +39,11 @@
   const mapEditor = useMapEditor();
   const { showShops, bgImage, activeShopId } = storeToRefs(mapEditor);
 
+  const props = defineProps<{
+    isMobileView: boolean;
+    moduleCode: string;
+  }>();
+
   const emit = defineEmits(['onOpen']);
 
   const stageRef = ref<Konva.Stage>();
@@ -66,11 +78,24 @@
     };
   };
 
-  const transformerConfig = {
+  const transformerConfig = ref({
     keepRatio: true,
     rotateEnabled: false,
-    enabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],
-  };
+    // enabledAnchors: ['top-left', 'top-right', 'bottom-left', 'bottom-right'],
+    enabledAnchors: !props.isMobileView
+      ? ['top-left', 'top-right', 'bottom-left', 'bottom-right']
+      : [],
+  });
+
+  watch(
+    () => props.isMobileView,
+    (v) => {
+      transformerConfig.value.enabledAnchors = !v
+        ? ['top-left', 'top-right', 'bottom-left', 'bottom-right']
+        : [];
+      updateTransformer();
+    },
+  );
 
   const handleStageMouseDown = (e) => {
     if (e.target.attrs.name === 'bg') {

+ 35 - 0
src/views/page-config/component/mapContainer/labelConfigMobile.ts

@@ -0,0 +1,35 @@
+import { MapWorkShopInfoItem } from '../../stores/useMapEditor';
+export const getIconConfig = (image: any) => {
+  return {
+    x: -25,
+    y: -25,
+    width: 50,
+    height: 50,
+    image: image,
+  };
+};
+
+export const getRectConfig = (shop: MapWorkShopInfoItem) => {
+  return {
+    x: 22,
+    y: -13,
+    fill: '#0000009C',
+    width: shop.name.length * shop.fontSize + 20,
+    height: 26,
+  };
+};
+
+export const getTextConfig = (shop: MapWorkShopInfoItem) => {
+  return {
+    x: 32,
+    y: -13,
+    text: shop.name,
+    fontSize: shop.fontSize,
+    fontFamily: 'TRENDS',
+    fill: shop.fontColor,
+    width: shop.name.length * shop.fontSize,
+    height: 26,
+    align: 'center',
+    verticalAlign: 'middle',
+  };
+};

+ 2 - 2
src/views/system-config/scene-manage/CompanyDrawer-shangfei.vue

@@ -154,7 +154,7 @@
       remark?: string;
       longitude?: number; //经度
       latitude?: number; //纬度
-      regionCode: string;
+      regionCode?: string;
     };
   }>();
 
@@ -188,7 +188,7 @@
     remark?: string; //备注,可用于添加经纬度,非必要
     longitude?: number; //经度
     latitude?: number; //纬度
-    regionCode: string;
+    regionCode?: string;
   }
 
   const ruleForm = reactive<RuleForm>({

+ 105 - 18
src/views/system-config/scene-manage/CompanyDrawer.vue

@@ -7,6 +7,7 @@
       @close="() => emit('onClose')"
       with-header="true"
       size="35%"
+      destroy-on-close
     >
       <template #header="{ titleId }">
         <p :id="titleId">{{ title }}</p>
@@ -38,10 +39,10 @@
             >
               <el-select v-model="item.tag" placeholder="请选择标签" style="width: 126px">
                 <el-option
-                  v-for="item1 in props.sceneList"
-                  :key="item1.id"
-                  :label="item1.name"
-                  :value="item1.id"
+                  v-for="scene in props.sceneList"
+                  :key="scene.id"
+                  :label="scene.name"
+                  :value="scene.id"
                 />
               </el-select>
               <img
@@ -50,10 +51,10 @@
                 style="width: 16px; margin-left: 2px; margin-right: 2px" />
               <el-select v-model="item.template" placeholder="请选择模板" style="width: 126px">
                 <el-option
-                  v-for="item2 in props.templateList"
-                  :key="item2.id"
-                  :label="item2.name"
-                  :value="item2.id"
+                  v-for="template in props.templateList"
+                  :key="template.id"
+                  :label="template.name"
+                  :value="template.id"
                 />
               </el-select>
               <img
@@ -77,10 +78,10 @@
         <el-form-item label="所在省市" prop="regionCode" required>
           <el-select v-model="ruleForm.regionCode" placeholder="请选择省市" style="width: 200px">
             <el-option
-              v-for="item in provinceList"
-              :key="item.regionCode"
-              :label="item.regionName"
-              :value="item.regionCode"
+              v-for="province in provinceList"
+              :key="province.regionCode"
+              :label="province.regionName"
+              :value="province.regionCode"
             />
           </el-select>
         </el-form-item>
@@ -101,6 +102,28 @@
             class="switchUse"
           />
         </el-form-item>
+        <el-form-item label="公司头像">
+          <el-upload
+            ref="uploadRef"
+            :class="{ 'no-el-upload': fileList.length > 0 }"
+            :action="actionUrl"
+            :on-preview="handlePictureCardPreview"
+            :on-remove="handleUploadRemove"
+            :on-success="handleUploadSuccess"
+            :before-upload="beforeThumbnailUpload"
+            :limit="1"
+            :headers="getHeaders()"
+            :data="{ bizType: 'COMPANY_THUMBNAIL' }"
+            list-type="picture-card"
+            v-model:file-list="fileList"
+          >
+            <!-- <img v-if="ruleForm.thumbnail" :src="ruleForm.thumbnail" />
+            <el-icon v-else><Plus /></el-icon> -->
+            <el-icon v-if="!ruleForm.thumbnail || ruleForm.thumbnail.length === 0"
+              ><Plus
+            /></el-icon>
+          </el-upload>
+        </el-form-item>
       </el-form>
       <div style="position: absolute; left: 108px; bottom: 67px">
         <el-button v-if="!props.comEdit" @click="resetDrawCom">重置</el-button>
@@ -109,8 +132,11 @@
           提交
         </el-button>
       </div>
-    </el-drawer></div
-  >
+    </el-drawer>
+    <el-dialog v-model="dialogVisible">
+      <img w-full :src="dialogImageUrl" alt="Preview Image" />
+    </el-dialog>
+  </div>
 </template>
 
 <script setup lang="ts">
@@ -128,7 +154,11 @@
   import { addCompany, editCompany } from '@/api/scene/sceneOperate';
   import { getProvinceList } from '@/api/system/region';
   import { useRequest } from 'vue-hooks-plus';
-  import { string } from 'vue-types';
+  import { Plus } from '@element-plus/icons-vue';
+  import { getHeaders } from '@/utils/http/axios';
+  import type { UploadRawFile, UploadFile } from 'element-plus';
+  import urlJoin from 'url-join';
+  import { useGlobSetting } from '@/hooks/setting';
 
   interface SelectItemType {
     tag: string;
@@ -150,10 +180,58 @@
       remark?: string;
       longitude?: number; //经度
       latitude?: number; //纬度
-      regionCode: string;
+      regionCode?: string;
+      thumbnail?: string;
     };
   }>();
 
+  const { urlPrefix } = useGlobSetting();
+
+  const actionUrl = computed(() => {
+    return urlJoin(urlPrefix!, `/issue/uploadPicture`);
+  });
+
+  const uploadRef = ref();
+
+  const dialogImageUrl = ref('');
+  const dialogVisible = ref(false);
+  const fileList = ref<UploadFile[]>([]);
+
+  onMounted(() => {
+    console.log('props.detail', props.detail.thumbnail);
+
+    if (props.detail.thumbnail) {
+      fileList.value.push({
+        name: '公司头像',
+        status: 'success',
+        uid: 1,
+        url: props.detail.thumbnail,
+      });
+    }
+  });
+  const beforeThumbnailUpload = (file: UploadRawFile) => {
+    if (file.type !== 'image/png' && file.type !== 'image/jpeg') {
+      ElMessage.error('仅支持上传png/jpg/jpeg格式的图片');
+      return false;
+    } else if (file.size / 1024 / 1024 > 10) {
+      ElMessage.error('上传图片大小不能超过10MB');
+      return false;
+    }
+    return true;
+  };
+  const handlePictureCardPreview = (file: UploadFile) => {
+    dialogImageUrl.value = file.url!;
+    dialogVisible.value = true;
+  };
+
+  const handleUploadRemove = () => {
+    ruleForm.thumbnail = '';
+  };
+
+  const handleUploadSuccess = (res) => {
+    ruleForm.thumbnail = res.data.url;
+  };
+
   const title = computed(() => {
     if (props.comEdit) {
       return '编辑公司';
@@ -184,7 +262,9 @@
     remark?: string; //备注,可用于添加经纬度,非必要
     longitude?: number; //经度
     latitude?: number; //纬度
-    regionCode: string;
+    regionCode?: string;
+    /** 公司缩略图 */
+    thumbnail?: string;
   }
 
   const ruleForm = reactive<RuleForm>({
@@ -240,6 +320,7 @@
       ruleForm.latitude = data.latitude;
       ruleForm.longitude = data.longitude;
       ruleForm.regionCode = data.regionCode;
+      ruleForm.thumbnail = data.thumbnail;
     },
     { immediate: true },
   );
@@ -309,6 +390,7 @@
           longitude: ruleForm.longitude,
           latitude: ruleForm.latitude,
           regionCode: ruleForm.regionCode,
+          thumbnail: ruleForm.thumbnail,
         };
         //提交数据并重置关闭el-draw
         addCompany(newComData)
@@ -378,6 +460,7 @@
         longitude: ruleForm.longitude,
         latitude: ruleForm.latitude,
         regionCode: ruleForm.regionCode,
+        thumbnail: ruleForm.thumbnail,
       };
       // 编辑上传
       editCompany(editNewCom)
@@ -409,4 +492,8 @@
   };
 </script>
 
-<style scoped></style>
+<style scoped>
+  :deep(.no-el-upload .el-upload--picture-card) {
+    display: none;
+  }
+</style>

+ 1 - 0
src/views/system-config/scene-manage/SceneManage.vue

@@ -428,6 +428,7 @@
         longitude: editedItem.value?.longitude!,
         latitude: editedItem.value?.latitude!,
         regionCode: editedItem.value?.regionCode,
+        thumbnail: editedItem.value?.thumbnail,
       };
     } else if (level.value === DATA_LEVEL.workshop && 'companyId' in editedItem.value!) {
       showDrawer.value = DrawerType.workshop;