2 Commits 847f48f057 ... 8b842fe0b3

Author SHA1 Message Date
  qpw 8b842fe0b3 项目权限控制的权限弹窗修复 2 months ago
  qpw 150073d0f9 弹窗 2 months ago

+ 1 - 1
src/api/gislayer/gisform/index.ts

@@ -80,7 +80,7 @@ export const GisFormApi = {
     return await request.get({ url: `/layer/gis-name/get-authority-user?layer=` + layer })
   },
   getTeamMember: async (params: any) => {
-    return await request.get({ url: `/layer/gis-name/get-member`, params })
+    return await request.get({ url: `/layer/gis-name/get-member0`, params })
   },
   addTeamMember: async (data: any) => {
     return await request.post({ url: `/layer/gis-name/add-member` , data })

+ 2 - 0
src/api/infra/file/index.ts

@@ -44,6 +44,8 @@ export const updateFile = (data: any) => {
   return request.upload({ url: '/infra/file/upload', data })
 }
 
+
+
 //上传缩略图
 export const uploadThumbnail = (data: any) => {
   return request.upload({ url: '/infra/file/uploadThumbnail', data })

+ 10 - 0
src/api/layer/gisname/index.ts

@@ -9,6 +9,7 @@ export interface GisNameVO {
   showitem: string // 需要显示为文本的字段
   symbolizeModel: string // 符号化模型
   textDisplay: string // 文本显示
+  shpFile: File
 }
 
 // shp名 API
@@ -28,6 +29,15 @@ export const GisNameApi = {
     return await request.post({ url: `/layer/gis-name/create`, data })
   },
 
+// 上传shp或gdb文件
+  createShp : (data: any) => {
+    return request.upload({ url: '/layer/gis-name/create-shp', data })
+  },
+
+  importGdb : (data: any) => {
+    return request.upload({ url: '/layer/gis-name/import-gdb', data })
+  },
+
   // 修改shp名
   updateGisName: async (data: GisNameVO) => {
     return await request.put({ url: `/layer/gis-name/update`, data })

+ 48 - 25
src/views/bpm/disbursement/AuthorityForm.vue

@@ -71,13 +71,24 @@
         <el-table-column label="可参与众筹" width="120" align="center">
           <template #default="scope">
             <el-switch
-                v-model="scope.row.inspection"
-                :active-value="1"
-                :inactive-value="0"
-                active-text="是"
-                inactive-text="否"
-                class="ml-2"
+              v-model="scope.row.inspection"
+              :active-value="1"
+              :inactive-value="0"
+              :disabled="isSpecialUser(scope.row)"
+            active-text="是"
+            inactive-text="否"
+            class="ml-2"
             />
+            <!-- 管理员状态提示 -->
+            <el-tooltip
+              v-if="isSpecialUser(scope.row)"
+              content="管理员默认开启且不可修改"
+              placement="top"
+            >
+      <span class="text-gray-400 ml-5px">
+        <Icon icon="ep:info-filled" />
+      </span>
+            </el-tooltip>
           </template>
         </el-table-column>
         <!-- 过期时间 -->
@@ -235,11 +246,12 @@ const getList = async () => {
       // 如果maturityTime是字符串,转换为Date对象以便于比较
       if (item.maturityTime) {
         if (typeof item.maturityTime === 'string') {
-          item.maturityTime = new Date(item.maturityTime);
+          item.maturityTime = new Date(item.maturityTime).getTime();
         }
       } else {
-        // 默认7天后过期
-        item.maturityTime = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
+        // 默认7天后过期 - 仅对新增用户设置默认值
+        const defaultDate = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
+        item.maturityTime = defaultDate.getTime();
       }
       
       // 如果createTime是字符串,转换为Date对象
@@ -258,8 +270,13 @@ const getList = async () => {
       } else {
         item.inspection = 0; // 默认不可巡检
       }
+
+      // 强制设置管理员的可巡检状态为开启
+      if (isSpecialUser(item)) {
+        item.inspection = 1  // 关键:覆盖接口返回值
+      }
       
-      // 更新过期状态和剩余天数
+      // 更新过期状态和剩余天数 - 使用后端返回的数据
       updateExpirationStatus(item);
       
       return item;
@@ -290,12 +307,12 @@ const handleUserChange = (row: UserRow) => {
         row.inspection = 0; // 默认不可巡检
       }
       if (!row.maturityTime) {
-        // 默认7天后过期
+        // 默认7天后过期 - 仅对新增用户设置默认值
         const defaultDate = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
-        // 格式化为字符串
-        row.maturityTime = defaultDate.toISOString().substring(0, 19).replace('T', ' ');
+        row.maturityTime = defaultDate.getTime(); // 使用时间戳格式
         // 更新过期状态
-        updateExpirationStatus(row);
+        row.valid = true;
+        row.daysLeft = 7;
       }
     }
   } else {
@@ -321,15 +338,17 @@ const handleDateChange = (row: UserRow) => {
 // 更新过期状态和剩余天数
 const updateExpirationStatus = (row: UserRow) => {
   if (row.maturityTime != null && row.maturityTime !== 0) {
-    const maturityDate = typeof row.maturityTime === 'string' 
-      ? new Date(row.maturityTime)
-      : row.maturityTime;
-    const now = new Date();
-    row.valid = maturityDate > now;
+    // 处理时间戳格式
+    const maturityTimestamp = typeof row.maturityTime === 'string' 
+      ? new Date(row.maturityTime).getTime()
+      : Number(row.maturityTime);
+    
+    const now = Date.now();
+    row.valid = maturityTimestamp > now;
     
     if (row.valid) {
       // 计算剩余天数
-      const diffTime = maturityDate.getTime() - now.getTime();
+      const diffTime = maturityTimestamp - now;
       row.daysLeft = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
     } else {
       row.daysLeft = 0;
@@ -341,11 +360,10 @@ const updateExpirationStatus = (row: UserRow) => {
 const handleAddRow = () => {
   // 默认7天后过期的日期
   const defaultDate = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
-  const formattedDate = defaultDate.toISOString().substring(0, 19).replace('T', ' ');
   
   const newRow = { 
     userId: undefined, 
-    maturityTime: formattedDate,
+    maturityTime: defaultDate.getTime(), // 使用时间戳格式
     onlyRead: 3, // 默认只读 
     valid: true,
     daysLeft: 7,
@@ -373,10 +391,15 @@ const updateSubmitData = () => {
     .map(row => {
       // 确保maturityTime是正确的格式
       let maturityTime = row.maturityTime;
-      if (maturityTime instanceof Date) {
+      
+      // 如果是时间戳,转换为日期字符串格式
+      if (typeof maturityTime === 'number') {
+        const date = new Date(maturityTime);
+        maturityTime = date.toISOString().substring(0, 19).replace('T', ' ');
+      } else if (maturityTime instanceof Date) {
         maturityTime = maturityTime.toISOString().substring(0, 19).replace('T', ' ');
       }
-      
+
       return {
         userId: row.userId,
         maturityTime: maturityTime,
@@ -423,7 +446,7 @@ const submitForm = async () => {
         if (maturityTime instanceof Date) {
           maturityTime = maturityTime.toISOString().substring(0, 19).replace('T', ' ');
         }
-        
+
         return {
           userId: row.userId,
           maturityTime: maturityTime,

+ 236 - 0
src/views/layer/gisname/ShpUploadForm.vue

@@ -0,0 +1,236 @@
+<template>
+  <Dialog :title="dialogTitle" v-model="dialogVisible" width="680px">
+    <el-form
+      ref="formRef"
+      :model="formData"
+      :rules="formRules"
+      label-width="120px"
+      label-position="left"
+    >
+      <!-- 文件类型切换 -->
+      <el-form-item label="文件类型" prop="fileType">
+        <el-radio-group
+          v-model="formData.fileType"
+          @change="handleTypeChange"
+          class="type-radio-group"
+        >
+          <el-radio-button label="shp">
+            <i class="el-icon-folder-opened"></i>
+            <span>SHP文件</span>
+          </el-radio-button>
+          <el-radio-button label="gdb">
+            <i class="el-icon-folder"></i>
+            <span>GDB文件</span>
+          </el-radio-button>
+        </el-radio-group>
+      </el-form-item>
+
+      <el-form-item label="图层名称" prop="shpName">
+        <el-input
+          v-model="formData.shpName"
+          placeholder="请输入图层名称(英文、下划线)"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item v-if="formData.fileType !== 'gdb'" label="图层描述" prop="description">
+        <el-input
+          v-model="formData.description"
+          :rows="3"
+          type="textarea"
+          placeholder="请输入图层描述"
+          clearable
+        />
+      </el-form-item>
+
+      <el-form-item :label="uploadLabel" prop="shpFile">
+        <el-upload
+          ref="uploadRef"
+          v-model:file-list="fileList"
+          :auto-upload="false"
+          :disabled="formLoading"
+          :limit="1"
+          :on-change="handleFileChange"
+          :on-error="submitFormError"
+          :on-exceed="handleExceed"
+          :on-success="submitFormSuccess"
+          :http-request="handleHttpRequest"
+          :accept="fileAccept"
+          drag
+          class="upload-container"
+        >
+          <template #trigger>
+            <div class="upload-trigger">
+              <i class="el-icon-upload text-4xl mb-2"></i>
+              <div class="el-upload__text">
+                <div>将{{ formData.fileType === 'shp' ? 'SHP' : 'GDB' }}压缩包拖到此处</div>
+                <em class="mt-1 text-gray-400">或点击上传</em>
+              </div>
+            </div>
+          </template>
+          <template #tip>
+            <div class="el-upload__tip text-center">
+              {{ fileList.length > 0 ? '✓ 文件已准备就绪' :
+              `请上传${formData.fileType === 'shp' ?
+                '包含.shp/.shx/.dbf等文件的ZIP压缩包' :
+                '包含.gdb目录的ZIP压缩包'}` }}
+            </div>
+          </template>
+        </el-upload>
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="dialogVisible = false">取消</el-button>
+      <el-button
+        type="primary"
+        :loading="formLoading"
+        @click="submitFileForm"
+      >
+        {{ formLoading ? '导入中...' : '确定' }}
+      </el-button>
+    </template>
+  </Dialog>
+</template>
+
+<script lang="ts" setup>
+import { ref, reactive, computed } from 'vue'
+import type { UploadRequestOptions } from "element-plus/es/components/upload/src/upload"
+import { GisNameApi } from "@/api/layer/gisname"
+
+const dialogVisible = ref(false)
+const formLoading = ref(false)
+const fileList = ref<File[]>([])
+const uploadRef = ref()
+
+// 计算属性
+const dialogTitle = computed(() => formData.value.fileType === 'shp' ? 'SHP文件导入' : 'GDB文件导入')
+const uploadLabel = computed(() => formData.value.fileType === 'shp' ? 'SHP压缩包' : 'GDB压缩包')
+const fileAccept = computed(() => '.zip')
+
+// 表单数据
+const formData = ref({
+  fileType: 'shp',
+  shpName: '',
+  description: ''
+})
+
+// 表单校验规则
+const formRules = reactive({
+  shpName: [
+    { required: true, message: '图层名称不能为空', trigger: 'blur' },
+    {
+      pattern: /^[a-z_][a-z0-9_]*$/,
+      message: '名称只能包含小写字母、数字和下划线,且不能以数字开头',
+      trigger: 'blur'
+    }
+  ]
+})
+
+const handleTypeChange = () => {
+  fileList.value = []
+  uploadRef.value?.clearFiles()
+}
+
+const handleHttpRequest = async (options: UploadRequestOptions) => {
+  const fd = new FormData()
+  fd.append('shpName', formData.value.shpName)
+  fd.append('description', formData.value.description)
+  fd.append('shpFile', options.file)
+
+  try {
+    const api = formData.value.fileType === 'shp' ? GisNameApi.createShp : GisNameApi.importGdb
+    const res = await api(fd)
+    return res.code === 0 ? Promise.resolve(res) : Promise.reject(res)
+  } catch (error) {
+    return Promise.reject(error)
+  }
+}
+
+const handleFileChange = (file: File) => {
+  if (!file.name.endsWith('.zip')) {
+    ElMessage.error('只能上传ZIP格式的压缩包')
+    fileList.value = []
+    return false
+  }
+}
+
+const submitFileForm = async () => {
+  if (!formData.value.shpName.match(/^[a-z_][a-z0-9_]*$/)) {
+    return ElMessage.error('图层名称格式错误')
+  }
+  if (fileList.value.length === 0) {
+    return ElMessage.error('请上传压缩包文件')
+  }
+
+  formLoading.value = true
+  try {
+    await uploadRef.value?.submit()
+  } finally {
+    formLoading.value = false
+  }
+}
+
+const emit = defineEmits(['success'])
+const submitFormSuccess = (response: any) => {
+  ElMessage.success(response.data?.featureCount ?
+    `导入成功,共${response.data.featureCount}个要素` : '导入成功')
+  resetForm()
+  emit('success')
+}
+
+const submitFormError = (error: Error) => {
+  ElMessage.error(`上传失败:${error.message || '未知错误'}`)
+}
+
+const handleExceed = () => {
+  ElMessage.error('每次只能上传一个压缩包!')
+}
+
+const resetForm = () => {
+  formData.value = { fileType: 'shp', shpName: '', description: '' }
+  fileList.value = []
+  dialogVisible.value = false
+  uploadRef.value?.clearFiles()
+}
+
+const open = () => {
+  resetForm()
+  dialogVisible.value = true
+}
+
+defineExpose({ open })
+</script>
+
+<style scoped>
+.type-radio-group {
+  gap: 16px;
+  margin: 16px 0;
+}
+
+.upload-container {
+  width: 100%;
+  border: 2px dashed var(--el-border-color);
+  border-radius: 8px;
+  transition: border-color 0.3s ease;
+
+  &:hover {
+    border-color: var(--el-color-primary);
+  }
+}
+
+.upload-trigger {
+  padding: 24px 0;
+  color: var(--el-color-info);
+
+  .el-icon-upload {
+    color: var(--el-color-primary);
+    margin-bottom: 12px;
+  }
+}
+
+.el-upload__tip {
+  color: var(--el-text-color-secondary);
+  margin-top: 8px;
+}
+</style>

+ 27 - 11
src/views/layer/gisname/index.vue

@@ -92,6 +92,14 @@
         >
           <Icon icon="ep:plus" class="mr-5px" /> 新增
         </el-button>
+        <el-button
+          type="danger"
+          plain
+          @click="openShpForm('create')"
+          v-hasPermi="['layer:gis-name:create']"
+        >
+          <Icon icon="ep:upload" class="mr-5px" /> 上传
+        </el-button>
         <el-button
           type="success"
           plain
@@ -109,7 +117,17 @@
   <ContentWrap>
     <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
       <el-table-column label="序号" align="center" prop="id" />
-      <el-table-column label="图层名" align="center" prop="shpName" />
+      <el-table-column label="图层名" align="center" prop="shpName" width="125"/>
+      <el-table-column label="shp类型" align="center" prop="shpType">
+        <template #default="scope">
+          <dict-tag :type="DICT_TYPE.LAYER_NAME_SHPTYPE" :value="scope.row.shpType" />
+        </template>
+      </el-table-column>
+<!--      <el-table-column label="需要点击展示的字段" align="center" prop="showitem" />-->
+<!--      <el-table-column label="文字标签" align="center" prop="labelItem" />-->
+<!--      <el-table-column label="符号化模型" align="center" prop="symbolizeModel" />-->
+<!--      <el-table-column label="文本显示" align="center" prop="textDisplay" />-->
+      <el-table-column label="描述" align="center" prop="description" width="180"/>
       <el-table-column
         label="创建时间"
         align="center"
@@ -124,16 +142,6 @@
         :formatter="dateFormatter"
         width="180px"
       />
-      <el-table-column label="shp类型" align="center" prop="shpType">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.LAYER_NAME_SHPTYPE" :value="scope.row.shpType" />
-        </template>
-      </el-table-column>
-      <el-table-column label="需要点击展示的字段" align="center" prop="showitem" />
-      <el-table-column label="文字标签" align="center" prop="labelItem" />
-      <el-table-column label="描述" align="center" prop="description" />
-      <el-table-column label="符号化模型" align="center" prop="symbolizeModel" />
-      <el-table-column label="文本显示" align="center" prop="textDisplay" />
       <el-table-column label="操作" align="center" width="250">
         <template #default="scope">
           <el-button
@@ -174,6 +182,7 @@
   <!-- 表单弹窗:添加/修改 -->
   <GisNameForm ref="formRef" @success="getList" />
   <AuthorityForm ref="authorityRef" @success="getList" />
+  <ShpUploadForm ref="shpUploadRef" @success="getList" />
 
 </template>
 
@@ -183,6 +192,7 @@ import { dateFormatter } from '@/utils/formatTime'
 import download from '@/utils/download'
 import { GisNameApi, GisNameVO } from '@/api/layer/gisname'
 import GisNameForm from './GisNameForm.vue'
+import ShpUploadForm from './ShpUploadForm.vue'
 
 import AuthorityForm from './AuthorityForm.vue'
 /** shp名 列表 */
@@ -241,6 +251,12 @@ const openForm = (type: string, id?: number) => {
   formRef.value.open(type, id)
 }
 
+/** 上传shp文件操作 */
+const shpUploadRef = ref()
+const openShpForm = (type: string, id?: number) => {
+  shpUploadRef.value.open(type, id)
+}
+
 /** 删除按钮操作 */
 const handleDelete = async (id: number) => {
   try {

File diff suppressed because it is too large
+ 483 - 171
yarn.lock


Some files were not shown because too many files changed in this diff