gemercheung преди 1 година
родител
ревизия
ca49ca0060
променени са 4 файла, в които са добавени 443 реда и са изтрити 12 реда
  1. 22 0
      src/api/mapOpt/list.ts
  2. 128 0
      src/views/map/addProjectModal.vue
  3. 34 12
      src/views/map/list.vue
  4. 259 0
      src/views/map/mapSelectModal.vue

+ 22 - 0
src/api/mapOpt/list.ts

@@ -4,10 +4,21 @@ import { BasicPageParams, BasicFetchResult } from '/@/api/model/baseModel';
 export type PageParams = BasicPageParams;
 export type PageParams = BasicPageParams;
 enum Api {
 enum Api {
   pageList = '/service/manage_jp/project/list',
   pageList = '/service/manage_jp/project/list',
+  saveOrUpdate = '/service/manage_jp/project/saveOrUpdate',
 }
 }
 
 
 type listType = {};
 type listType = {};
 
 
+export type MapOptType = {
+  id?: number;
+  projectName: string;
+  projectSn: string;
+  isShow: number;
+  lat?: number;
+  lon?: number;
+  alt?: number;
+};
+
 export type ListGetResultModel = BasicFetchResult<listType>;
 export type ListGetResultModel = BasicFetchResult<listType>;
 /**
 /**
  * @description: Get sample list value
  * @description: Get sample list value
@@ -23,3 +34,14 @@ export const ListApi = (params: PageParams) =>
       ignoreCancelToken: true,
       ignoreCancelToken: true,
     },
     },
   });
   });
+
+export const AddOptOrUpdateApi = (params: MapOptType) =>
+  defHttp.post<any>({
+    url: Api.saveOrUpdate,
+    params,
+    data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });

+ 128 - 0
src/views/map/addProjectModal.vue

@@ -0,0 +1,128 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="register" title="新增项目" @ok="handleSubmit">
+    <div class="p-20px">
+      <BasicForm @register="registerForm">
+        <template #location>
+          <div class="map-select">
+            <a-input v-model:value="location" disabled />
+            <a-button type="default" @click="$emit('open-map')">地图选择</a-button>
+          </div>
+        </template>
+        <!-- <template #label="{ model, field }">
+          {{ model[field] }}
+        </template>
+        <template #process> {{ downloadInfo.process }} % </template>
+        <template #status> {{ downloadInfo.status }} </template> -->
+      </BasicForm>
+    </div>
+    <template #centerFooter> </template>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { computed, defineComponent, ref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useI18n } from '/@/hooks/web/useI18n';
+
+  const { t } = useI18n();
+  const schemas: FormSchema[] = [
+    {
+      field: 'projectName',
+      label: '项目名称',
+      component: 'Input',
+      colProps: {
+        span: 24,
+      },
+    },
+    {
+      field: 'projectSn',
+      label: '项目编号',
+      component: 'Input',
+      colProps: {
+        span: 24,
+      },
+    },
+    {
+      field: 'location',
+      label: '位置',
+      component: 'Input',
+      slot: 'location',
+      colProps: {
+        span: 24,
+      },
+    },
+    {
+      field: 'isShow',
+      label: '是否展示',
+      component: 'Switch',
+      colProps: {
+        span: 24,
+      },
+      componentProps: {
+        defaultChecked: true,
+      },
+    },
+  ];
+
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      currentLatLng: {
+        type: Object as PropType<{
+          lat: number;
+          lng: number;
+        }>,
+      },
+    },
+    emits: ['register', 'success', 'open-map'],
+    setup(props) {
+      // const { createMessage } = useMessage();
+      const sceneNum = ref('');
+      const location = computed(() =>
+        props.currentLatLng ? `${props.currentLatLng?.lat}, ${props.currentLatLng?.lng}` : '',
+      );
+
+      const [registerForm, { setFieldsValue }] = useForm({
+        schemas: schemas,
+        labelWidth: 100,
+        showActionButtonGroup: false,
+
+        actionColOptions: {
+          span: 24,
+        },
+        // submitFunc: handleSubmit,
+      });
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+
+      function onDataReceive(data) {
+        console.log('Data Received', data, data.num);
+
+        setFieldsValue({
+          ...data,
+        });
+
+        sceneNum.value = data.num;
+      }
+      const handleSubmit = async () => {};
+
+      return {
+        t,
+        register,
+        schemas,
+        handleSubmit,
+        closeModal,
+        registerForm,
+        location,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .map-select {
+    display: flex;
+    flex-direction: row;
+    gap: 0 20px;
+  }
+</style>

+ 34 - 12
src/views/map/list.vue

@@ -1,12 +1,20 @@
 <template>
 <template>
   <div class="p-4">
   <div class="p-4">
     <BasicTable @register="registerTable">
     <BasicTable @register="registerTable">
-      <template #toolbar> </template>
+      <template #toolbar>
+        <a-button type="primary" @click="handleCreate">新增项目</a-button>
+      </template>
     </BasicTable>
     </BasicTable>
+    <AddProjectModal
+      @register="registerAddProjectModal"
+      @open-map="handleSelectMap"
+      :currentLatLng="currentLatLng"
+    />
+    <MapSelectModal @register="registerMapSelectModal" @update="handleMapChose" />
   </div>
   </div>
 </template>
 </template>
 <script lang="ts">
 <script lang="ts">
-  import { defineComponent, computed } from 'vue';
+  import { defineComponent, computed, ref } from 'vue';
   import { BasicTable, useTable, BasicColumn, FormProps } from '/@/components/Table';
   import { BasicTable, useTable, BasicColumn, FormProps } from '/@/components/Table';
   import { useMessage } from '/@/hooks/web/useMessage';
   import { useMessage } from '/@/hooks/web/useMessage';
 
 
@@ -16,17 +24,18 @@
   import { useI18n } from '/@/hooks/web/useI18n';
   import { useI18n } from '/@/hooks/web/useI18n';
   // import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
   // import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
   import { useGo } from '/@/hooks/web/usePage';
   import { useGo } from '/@/hooks/web/usePage';
-  // import { Time } from '/@/components/Time';
   import { useLocaleStore } from '/@/store/modules/locale';
   import { useLocaleStore } from '/@/store/modules/locale';
-
+  import AddProjectModal from './addProjectModal.vue';
+  import MapSelectModal from './mapSelectModal.vue';
   const localeStore = useLocaleStore();
   const localeStore = useLocaleStore();
 
 
   const isJA = computed(() => localeStore.getLocale === 'ja');
   const isJA = computed(() => localeStore.getLocale === 'ja');
 
 
   export default defineComponent({
   export default defineComponent({
-    components: { BasicTable },
+    components: { BasicTable, AddProjectModal, MapSelectModal },
     setup() {
     setup() {
-      const [register, { openModal }] = useModal();
+      const [registerAddProjectModal, { openModal: openAddProjectModal }] = useModal();
+      const [registerMapSelectModal, { openModal: openMapModal }] = useModal();
       const { createMessage } = useMessage();
       const { createMessage } = useMessage();
       const go = useGo();
       const go = useGo();
       const { t } = useI18n();
       const { t } = useI18n();
@@ -34,6 +43,7 @@
         {
         {
           title: 'ID',
           title: 'ID',
           dataIndex: 'id',
           dataIndex: 'id',
+          ifShow: false,
           fixed: 'left',
           fixed: 'left',
           width: 60,
           width: 60,
         },
         },
@@ -62,13 +72,13 @@
           width: isJA.value ? 160 : 80,
           width: isJA.value ? 160 : 80,
         },
         },
       ];
       ];
-
+      const currentLatLng = ref();
       const searchForm: Partial<FormProps> = {
       const searchForm: Partial<FormProps> = {
         labelWidth: 100,
         labelWidth: 100,
         schemas: [
         schemas: [
           {
           {
             field: 'phoneNum',
             field: 'phoneNum',
-            label: '员工邮箱',
+            label: '项目名称',
             component: 'Input',
             component: 'Input',
             colProps: {
             colProps: {
               xl: 5,
               xl: 5,
@@ -93,16 +103,28 @@
         bordered: true,
         bordered: true,
       });
       });
 
 
-      function handleOpenModal(record: Recordable) {
-        openModal(true, record);
+      function handleCreate() {
+        openAddProjectModal(true);
+      }
+      function handleSelectMap() {
+        openMapModal(true);
       }
       }
+      function handleMapChose(coord) {
+        console.log('handleMapChose', coord);
+        currentLatLng.value = coord;
+      }
+
       return {
       return {
         registerTable,
         registerTable,
         createMessage,
         createMessage,
         t,
         t,
         go,
         go,
-        handleOpenModal,
-        register,
+        registerAddProjectModal,
+        handleCreate,
+        registerMapSelectModal,
+        handleSelectMap,
+        handleMapChose,
+        currentLatLng,
       };
       };
     },
     },
   });
   });

+ 259 - 0
src/views/map/mapSelectModal.vue

@@ -0,0 +1,259 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="地图选择"
+    @ok="handleSubmit"
+    @cancel="handleCancel"
+    :width="828"
+    :minHeight="500"
+    centered
+  >
+    <GoogleMap
+      ref="mapRef"
+      api-key="AIzaSyBGUvCR1bppO9pfuS0MUWzuftiZ127y4Os"
+      mapId="DEMO_MAP_ID"
+      :center="center"
+      :map-type-control="false"
+      :disable-default-ui="true"
+      :language="lang"
+      region="JP"
+      :zoom="7"
+      map-type-id="roadmap"
+      :mapTypeControlOptions="{
+        style: 1,
+        position: 3,
+      }"
+      style="width: 800px; height: 500px"
+      @click="handleMapClick"
+      v-loading="loadingRef"
+      :loading-tip="t('common.loadingText')"
+    >
+      <CustomControl position="TOP_LEFT">
+        <div class="p-20px">
+          <a-input id="pac-input" allow-clear />
+        </div>
+      </CustomControl>
+    </GoogleMap>
+    <div v-if="searchMarker.lng || searchMarker.lat">
+      纬度 {{ searchMarker.lat }}, 经度 {{ searchMarker.lng }}</div
+    >
+
+    <template #centerFooter> </template>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { computed, defineComponent, ref, watch } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { FormSchema, useForm } from '/@/components/Form/index';
+
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import {
+    GoogleMap,
+    // AdvancedMarker,
+    // MarkerCluster,
+    // // InfoWindow,
+    CustomControl,
+  } from 'vue3-google-map';
+  import { useLocaleStore } from '/@/store/modules/locale';
+
+  const { t } = useI18n();
+  const schemas: FormSchema[] = [
+    {
+      field: 'projectName',
+      label: '项目名称',
+      component: 'Input',
+      colProps: {
+        span: 24,
+      },
+    },
+    {
+      field: 'projectSn',
+      label: '项目编号',
+      component: 'Input',
+      colProps: {
+        span: 24,
+      },
+    },
+    {
+      field: 'location',
+      label: '位置',
+      component: 'Input',
+      slot: 'location',
+      colProps: {
+        span: 24,
+      },
+    },
+    {
+      field: 'isShow',
+      label: '是否展示',
+      component: 'Switch',
+      colProps: {
+        span: 24,
+      },
+      componentProps: {
+        defaultChecked: true,
+      },
+    },
+  ];
+  const localeStore = useLocaleStore();
+  export default defineComponent({
+    components: { BasicModal, GoogleMap, CustomControl },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['register', 'success', 'update'],
+    setup(_, { emit }) {
+      // const { createMessage } = useMessage();
+      const sceneNum = ref('');
+      const location = ref('');
+      const loadingRef = ref(true);
+      const center = { lat: 35.717, lng: 139.731 };
+      const mapRef = ref();
+      const searchMarker = ref({ lat: 0, lng: 0 });
+      const searchMarkerRef = ref();
+
+      const lang = computed(() => localeStore.getLocale);
+
+      const [registerForm, { setFieldsValue }] = useForm({
+        schemas: schemas,
+        labelWidth: 100,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+        // submitFunc: handleSubmit,
+      });
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      watch(
+        () => mapRef.value?.ready,
+        (ready) => {
+          if (!ready) return;
+          console.log('ready', ready);
+
+          loadingRef.value = false;
+          const map = mapRef.value.map;
+          if (map) {
+            const defaultBounds = {
+              north: center.lat + 0.1,
+              south: center.lat - 0.1,
+              east: center.lng + 0.1,
+              west: center.lng - 0.1,
+            };
+            const input = document.getElementById('pac-input') as HTMLInputElement;
+            const options = {
+              bounds: defaultBounds,
+              componentRestrictions: { country: 'jp' },
+              fields: ['address_components', 'geometry', 'icon', 'name'],
+              strictBounds: false,
+            };
+            // @ts-ignore
+            const autocomplete = new google.maps.places.Autocomplete(input, options);
+            // debugger;
+
+            console.log('map', map);
+            autocomplete.bindTo('bounds', map);
+            // @ts-ignore
+            searchMarkerRef.value = new google.maps.Marker({
+              map,
+              // @ts-ignore
+              anchorPoint: new google.maps.Point(0, -29),
+            });
+
+            autocomplete.addListener('place_changed', () => {
+              searchMarkerRef.value.setVisible(false);
+
+              const place = autocomplete.getPlace();
+
+              if (!place.geometry || !place.geometry.location) {
+                // window.alert("No details available for input: '" + place.name + "'");
+                return;
+              }
+
+              // If the place has a geometry, then present it on a map.
+              if (place.geometry.viewport) {
+                map.fitBounds(place.geometry.viewport);
+              } else {
+                map.setCenter(place.geometry.location);
+                map.setZoom(17);
+              }
+
+              searchMarker.value.lat = place.geometry.location.lat();
+              searchMarker.value.lng = place.geometry.location.lng();
+              console.log('last-get', searchMarker.value);
+              searchMarkerRef.value.setPosition(place.geometry.location);
+              searchMarkerRef.value.setVisible(true);
+            });
+          }
+        },
+        {
+          deep: true,
+        },
+      );
+
+      function onDataReceive(data) {
+        console.log('Data Received', data, data.num);
+
+        setFieldsValue({
+          ...data,
+        });
+
+        sceneNum.value = data.num;
+      }
+
+      const resetMapview = () => {
+        searchMarker.value = { lat: 0, lng: 0 };
+        searchMarkerRef.value?.setVisible(false);
+        mapRef.value?.map?.setCenter(center);
+        mapRef.value?.map?.setZoom(7);
+        const input = document.getElementById('pac-input') as HTMLInputElement;
+        if (input) {
+          input.value = '';
+        }
+      };
+      const handleMapClick = async (event) => {
+        const { lat, lng } = event.latLng;
+        searchMarker.value.lat = lat();
+        searchMarker.value.lng = lng();
+        searchMarkerRef.value?.setVisible(true);
+        searchMarkerRef.value?.setPosition(searchMarker.value);
+      };
+      const handleSubmit = async () => {
+        if (searchMarker.value.lat || searchMarker.value.lng) {
+          emit('update', searchMarker.value);
+        }
+        closeModal();
+        resetMapview();
+      };
+      const handleCancel = async () => {
+        resetMapview();
+      };
+      return {
+        t,
+        register,
+        schemas,
+        handleSubmit,
+        closeModal,
+        registerForm,
+        location,
+        handleMapClick,
+        loadingRef,
+        lang,
+        mapRef,
+        center,
+        searchMarker,
+        handleCancel,
+        // searchMarkerShow,
+      };
+    },
+  });
+</script>
+<style lang="less" scoped>
+  .map-select {
+    display: flex;
+    flex-direction: row;
+    gap: 0 20px;
+  }
+</style>