沈丘营商办后台前端项目
wjt
2024-07-22 225e92ed4fd01dd9be529d7f9e5e546e05a0d277
添加来访信息
12个文件已添加
5个文件已修改
1430 ■■■■■ 已修改文件
.env.development 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
index.html 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/system/company/company.ts 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icon/icon1.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icon/icon2.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icon/icon3.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/icon/icon4.png 补丁 | 查看 | 原始文档 | blame | 历史
src/permission.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/infomanger/infoLook/components/createQrcode.vue 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/infomanger/infoLook/components/export.vue 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/infomanger/infoLook/components/exportRecord.vue 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/infomanger/infoLook/components/judge.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/infomanger/infoLook/index.vue 318 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/components/selectColor.vue 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/components/theme.vue 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/indexMarge.vue 552 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
.env.development
@@ -1,10 +1,11 @@
# 页面标题
VITE_APP_TITLE = 入企扫码
VITE_APP_TITLE = 惠企执法
# 开发环境配置
VITE_APP_ENV = 'development'
VITE_APP_BASE = 'http://172.16.61.34:8089'
# VITE_APP_BASE = 'http://172.16.61.31:8089'
VITE_APP_BASE = 'http://172.16.60.184:8089'
# VITE_APP_BASE = 'http://172.16.61.34:8089'
#VITE_APP_BASE = 'http://localhost:8089'
index.html
@@ -7,6 +7,8 @@
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
    <!-- <link rel="icon" href="/logo.ico" /> -->
    <title>惠企执法</title>
    <script src='//webapi.amap.com/maps?v=2.0&key=a3472b04ae282cabb61670b13c7b90ab' type="text/javascript"></script>
    <script src="//webapi.amap.com/ui/1.1/main.js"></script>
    <!--[if lt IE 11
      ]><script>
        window.location.href = "/html/ie.html";
src/api/system/company/company.ts
@@ -327,3 +327,26 @@
    params: data
  })
}
// /enforce/company/log/list
export function listCompanyLog(data) {
  return request({
    url: `/enforce/company/log/list`,
    method: 'get',
    params: data
  })
}
// /enforce/company/log/upd
export function updCompanyLog(data) {
  return request({
    url: `/enforce/company/log/upd`,
    method: 'post',
    data: data
  })
}
// /enforce/company/log/{ids}
export function delCompanyLog(data) {
  return request({
    url: `/enforce/company/log/${data.delId}`,
    method: 'DELETE',
  })
}
src/assets/icon/icon1.png
src/assets/icon/icon2.png
src/assets/icon/icon3.png
src/assets/icon/icon4.png
src/permission.ts
@@ -11,7 +11,7 @@
NProgress.configure({ showSpinner: false });
const whiteList = ["/login", "/register"];
const whiteList = ["/login", "/register", "/main"];
router.beforeEach((to, from, next) => {
  NProgress.start();
src/router/index.ts
@@ -1,6 +1,7 @@
import { createWebHistory, createRouter, RouteRecordRaw } from "vue-router";
/* Layout */
import Layout from "@/layout/index.vue";
import path from "path";
/**
 * Note: 路由配置项
@@ -58,6 +59,10 @@
    hidden: true,
  },
  {
    path: '/main',
    component: () => import("@/views/main/indexMarge.vue"),
  },
  {
    path: "",
    component: Layout,
    redirect: "/home",
src/views/infomanger/infoLook/components/createQrcode.vue
New file
@@ -0,0 +1,105 @@
<template>
  <el-dialog title="二维码"  v-model="dialogVisible" width="300px" @close="closeDialog">
    <div class="text-center">
      <vueQr ref="query" background="#fff" :text="info.companyCode"></vueQr>
      <div style="font-weight: bold;margin-bottom: 10px;">沈丘惠企执法</div>
      <div>{{ info.companyName }}</div>
      <div style="margin-top: 10px;">
        <el-link @click="downImage" type="primary">下载企业码</el-link>
      </div>
    </div>
    <canvas ref="canvasRef" style="position: absolute; left: 0; top: 2210px;background-color: white; display: none;"></canvas>
  </el-dialog>
</template>
<script lang="ts" setup>
import vueQr from 'vue-qr/src/packages/vue-qr.vue'
let dialogVisible = ref(false)
const canvasRef = ref()
const info = ref({})
const query = ref()
function openDialog(row) {
  // console.log(row)
  info.value = row
  dialogVisible.value = true
}
function closeDialog() {
  dialogVisible.value = false
}
function downImage() {
  drawText()
 const imageUrl = canvasRef.value.toDataURL('image/png')
  // console.log(query.value.imgUrl)
  let aLink = document.createElement('a')
      let blob = base64ToBlob(imageUrl)
      let evt = document.createEvent("HTMLEvents")
      evt.initEvent("click", true, true) // initEvent 不加后两个参数在FF下会报错  事件类型,是否冒泡,是否阻止浏览器的默认行为
      aLink.download = "二维码.png"
      aLink.href = URL.createObjectURL(blob);
      // aLink.dispatchEvent(evt);
      aLink.click()
}
function drawText() {
      const canvas = canvasRef.value;
      canvas.width = 350;
      canvas.height = 380;
      canvas.style.width = '350px';
      canvas.style.height = '380px';
      const ctx = canvas.getContext('2d');
      ctx.fillStyle  = "#fff"
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      let img = new Image();
      img.src = query.value.imgUrl;
      const text = info.value.companyName;
      ctx.drawImage(img, 10, 0, 320, 320);
      // ctx.font = '20px Arial';
      ctx.textAlign = 'center';
      ctx.fillStyle = '#000';
      // ctx.setFontWeight('bold')
      ctx.font ='bold 20px Arial'
      wrapText(ctx, "沈丘惠企执法", 180, 320, 350, 40)
      // ctx.setFontWeight('normal')
      ctx.font ="20px Arial"
      wrapText(ctx, text, 180, 350, 350, 20)
    }
    function wrapText(context, text, x, y, maxWidth, lineHeight) {
    var words = text.split('');
    var line = '';
    for(var n = 0; n < words.length; n++) {
        var testLine = line + words[n] + ' ';
        var metrics = context.measureText(testLine);
        var testWidth = metrics.width;
        if (testWidth > maxWidth && n > 0) {
            context.fillText(line, x, y);
            line = words[n] + ' ';
            y += lineHeight;
        }
        else {
            line = testLine;
        }
    }
    if(line) {
      context.fillText(line, x, y);
    }
}
function   base64ToBlob(code) {
      let parts = code.split(';base64,')
      let contentType = parts[0].split(':')[1]
      let raw = window.atob(parts[1])
      let rawLength = raw.length
      let uInt8Array = new Uint8Array(rawLength)
      for (let i = 0; i < rawLength; ++i) {
        uInt8Array[i] = raw.charCodeAt(i)
      }
      return new Blob([uInt8Array], {type: contentType})
    }
defineExpose({
  openDialog,
  closeDialog
})
</script>
<style>
</style>
src/views/infomanger/infoLook/components/export.vue
New file
@@ -0,0 +1,63 @@
<template>
  <el-dialog title="用户导入" v-model="dialogVisible" width="900px" append-to-body @close="cloaseDialog"
  >
    <el-form label-width="80px">
      <el-form-item label="下载模板">
        <el-link type="primary" @click="downLoad">企业信息导入模板.xlsx</el-link>
      </el-form-item>
      <el-form-item label="选取文件">
        <FileUpload :limit="1" :fileType="['cvs', 'xlsx']" v-model="form.exportNews.file" @resList="resList"></FileUpload>
      </el-form-item>
    </el-form>
    <template #footer>
      <div style="text-align: center;">
        <el-button @click="cloaseDialog" >关闭</el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessageBox } from 'element-plus'
import FileUpload from '@/components/FileUpload/handlerImport.vue'
import { download  as downloadHttp} from '@/utils/request'
import { downTemplate, importTemplate, doImport, exportTemplate } from '@/api/system/company/company'
const { proxy } = getCurrentInstance();
const dialogVisible = ref(false)
const emit = defineEmits()
const form = reactive({
  exportNews: {}
})
function openDialog() {
  dialogVisible.value = true
}
function cloaseDialog() {
  dialogVisible.value = false
}
function downLoad() {
  exportTemplate().then(val => {
    downloadHttp('/tool/file/download', {
      fileName: val.msg,
      delete: true
    }, "企业信息模板.xlsx")
  })
}
function startExport() {
  uploadFile()
}
function resList(row) {
  cloaseDialog()
  emit('resList', row)
}
defineExpose({
  openDialog,
  cloaseDialog
})
</script>
<style scoped>
.dialog-footer button:first-child {
  margin-right: 10px;
}
</style>
src/views/infomanger/infoLook/components/exportRecord.vue
New file
@@ -0,0 +1,155 @@
<template>
   <el-dialog title="导入记录" v-model="dialogVisible" width="1200px" append-to-body @close="closeDialog"
  >
    <el-table :data="recordValue" border>
      <el-table-column label="企业名(企业全称)" prop="companyName">
        <template #default="scope">
          <div class="flex-box-per">
            <el-input v-model="scope.row.companyName" @blur="checkImport(scope.row, scope.$index)"></el-input>
            <el-tooltip  v-if="scope.row.errorList.length && scope.row.errorList.find(item => item.index == 0)" :content="scope.row.errorList.find(item => item.index == 0).msg">
              <div class="ml5">
                <el-icon size="large" color="red" class="ml5"><CircleCloseFilled /></el-icon>
              </div>
            </el-tooltip>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="统一社会信用代码" prop="companyCode">
        <template #default="scope">
          <div class="flex-box-per">
            <el-input v-model="scope.row.companyCode"  @blur="checkImport(scope.row, scope.$index)"></el-input>
            <el-tooltip  v-if="scope.row.errorList.length && scope.row.errorList.find(item => item.index == 1)" :content="scope.row.errorList.find(item => item.index == 1).msg">
              <div class="ml5">
                <el-icon size="large" color="red" class="ml5"><CircleCloseFilled /></el-icon>
              </div>
            </el-tooltip>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="企业联系人" prop="companyUser">
        <template #default="scope">
          <div class="flex-box-per">
            <el-input v-model="scope.row.companyUser"  @blur="checkImport(scope.row, scope.$index)"></el-input>
            <el-tooltip  v-if="scope.row.errorList.length && scope.row.errorList.find(item => item.index == 2)" :content="scope.row.errorList.find(item => item.index == 2).msg">
              <div class="ml5" v-if="scope.row.errorList.length &&scope.row.errorList.find(item => item.index == 2)">
              <el-icon size="large" color="red" class="ml5"><CircleCloseFilled /></el-icon>
            </div>
            </el-tooltip>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="联系人电话" prop="companyPhone">
        <template #default="scope">
          <div class="flex-box-per">
            <el-input type="numer" :maxlength="11" v-model="scope.row.companyPhone"  @blur="checkImport(scope.row, scope.$index, 'companyPhone')"></el-input>
            <el-tooltip v-if="scope.row.errorList.length && scope.row.errorList.find(item => item.index == 3)" :content="scope.row.errorList.find(item => item.index == 3).msg">
              <div class="ml5">
              <el-icon size="large" color="red" class="ml5"><CircleCloseFilled /></el-icon>
            </div>
            </el-tooltip>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="企业地址" prop="companyAddress">
        <template #default="scope">
          <div class="flex-box-per">
            <el-input v-model="scope.row.companyAddress"  @blur="checkImport(scope.row, scope.$index)"></el-input>
            <el-tooltip v-if="scope.row.errorList.length && scope.row.errorList.find(item => item.index == 4)" :content="scope.row.errorList.find(item => item.index == 4).msg">
              <div class="ml5" v-if="scope.row.errorList.length && scope.row.errorList.find(item => item.index == 4)">
              <el-icon size="large" color="red" class="ml5"><CircleCloseFilled /></el-icon>
            </div>
            </el-tooltip>
          </div>
        </template>
      </el-table-column>
      <el-table-column label="备注" prop="mark">
        <template #default="scope">
          <div class="flex-box-per">
            <el-input v-model="scope.row.mark"  @blur="checkImport(scope.row, scope.$index)"></el-input>
            <el-tooltip v-if="scope.row.errorList.length && scope.row.errorList.find(item => item.index == 5)" :content="scope.row.errorList.find(item => item.index == 5).msg">
              <div class="ml5">
              <el-icon size="large" color="red" class="ml5"><CircleCloseFilled /></el-icon>
            </div>
            </el-tooltip>
          </div>
        </template>
      </el-table-column>
    </el-table>
    <template #footer>
      <div class="dialog-footer">
        <el-button @click="closeDialog">取 消</el-button>
        <el-button type="primary" @click="addCompany">确 定</el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script setup lang="ts">
import { checkImport as checkImportHttp, saveImport } from '@/api/system/company/company'
import { ElMessage} from 'element-plus'
const dialogVisible = ref(false)
const emits = defineEmits()
const props = defineProps({
  recordRow: { type: Array, default: () => [] },
})
const recordValue = ref([])
watch(() => props.recordRow, (newValue) => {
  // console.log(props.recordRow)
  recordValue.value = newValue
})
function openDialog() {
  dialogVisible.value = true
}
function closeDialog() {
  dialogVisible.value = false
}
function checkImport(row, index, item) {
  // row.companyPhone
  if(item && item == 'companyPhone') {
    if(row.companyPhone) {
      const reg = /^1[3|4|5|6|7|8|9][0-9]\d{8}$/
      if(!reg.test(row.companyPhone)){
        ElMessage.error('请输入正确的手机号')
      }
    }
  }
  checkImportHttp({voList: [row]}).then(val => {
    // recordValue.value.splice(index, 1, val.data.voList[0])
    recordValue.value[index] = val.data.voList[0]
    // ElMessage.success('修改成功')
  })
}
function addCompany() {
  saveImport({voList: recordValue.value}).then(val =>{
    ElMessage.success('导入成功')
    closeDialog()
    emits('uploadList')
  })
}
defineExpose({
  openDialog,
  closeDialog
})
</script>
<style >
.dialog-footer{
  text-align: center;
}
.flex-box-per{
  display: flex;
  justify-content: flex-start;
  align-items: center;
}
.ml5{
  /* margin-left: 5px; */
  line-height: 15px;
}
</style>
src/views/infomanger/infoLook/components/judge.vue
New file
@@ -0,0 +1,67 @@
<template>
    <el-dialog title="审核" v-model="dialogVisible" width="900px" append-to-body @close="cloaseDialog"
  >
    <el-form>
      <!-- <el-form-item label="审核类型">
        <el-select style="width: 200px;" v-model="form.checkType">
          <el-option label="企业审批" value="1"></el-option>
          <el-option label="企业审批" value="2"></el-option>
        </el-select>
      </el-form-item> -->
      <el-form-item label="审核状态">
        <el-radio-group v-model="form.checkStatus" class="ml-4">
          <el-radio value="1" size="large">通过</el-radio>
          <el-radio value="-1" size="large">拒绝</el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="审核说明">
        <el-input    type="textarea"      v-model="form.checkReason"  ></el-input>
      </el-form-item>
    </el-form>
    <template #footer>
      <div style="text-align: center;">
        <el-button @click="cloaseDialog" >关闭</el-button>
        <el-button @click="checkOrder" type="primary">确认</el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script setup lang="ts">
import { checkOrder as httpCheck } from '@/api/system/company/company'
import { ElMessage } from 'element-plus'
const dialogVisible = ref(false)
const info = ref({})
const emit:any = defineEmits()
const form: any = reactive({
  checkStatus: '1'
})
const cloaseDialog = () => {
  dialogVisible.value = false
}
const openDialog = (row: { companyId?: any }) => {
  info.value = row
  form['ids'] = [row.companyId]
  form['checkType'] = 1
  form['checkReason'] = ''
  dialogVisible.value = true
}
function checkOrder() {
  if(!form['checkStatus']) {
    ElMessage.error('请填写审核状态')
    return
  }
  if(form['checkStatus'] == -1 && !form.checkReason) {
    ElMessage.error('请填写审核说明')
    return
  }
  httpCheck(form).then(res => {
    cloaseDialog()
    emit('upload')
  })
}
defineExpose({
  openDialog,
  cloaseDialog
})
</script>
src/views/infomanger/infoLook/index.vue
New file
@@ -0,0 +1,318 @@
<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryRef"  class="evenly-distributed-labels" :inline="true" v-show="showSearch" label-width="80px" label-position="left">
      <el-form-item label="企业名称" prop="companyName">
        <el-input v-model="queryParams.companyName" placeholder="请输入企业名称" clearable style="width: 200px" @keyup.enter="handleQuery" />
      </el-form-item>
      <el-form-item label="企业编号" prop="companyCode">
        <el-input v-model="queryParams.companyCode" placeholder="请输入企业编号" clearable style="width: 200px" @keyup.enter="handleQuery" />
      </el-form-item>
      <el-form-item label="联系人" prop="companyUser">
        <el-input v-model="queryParams.companyUser" placeholder="请输入联系人" clearable style="width: 200px" @keyup.enter="handleQuery" />
      </el-form-item>
      <el-form-item label="手机号" prop="companyPhone">
        <el-input v-model="queryParams.companyPhone" type="number" placeholder="请输入手机号" clearable style="width: 200px" @keyup.enter="handleQuery" />
      </el-form-item>
      <el-form-item>
        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <el-table
      v-if="refreshTable"
      v-loading="loading"
      :data="deptList"
      row-key="deptId"
      :default-expand-all="isExpandAll"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    >
      <el-table-column  prop="companyName" label="企业名称" minWidth="300"></el-table-column>
      <!-- <el-table-column prop="companyName" label="企业类型" width="200"></el-table-column> -->
      <el-table-column prop="companyUser" label="联系人" width="180"></el-table-column>
      <el-table-column prop="companyPhone" label="手机号码" width="120"></el-table-column>
      <el-table-column prop="comeTime" label="创建时间" width="200"></el-table-column>
      <el-table-column prop="comeContent" label="来访事项" width="200"></el-table-column>
      <el-table-column prop="userNum" label="随行人数" width="200"></el-table-column>
      <el-table-column prop="remark" label="备注" ></el-table-column>
      <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width" width="240">
        <template #default="scope">
          <el-link type="success" v-if="scope.row.checkStatus < 2" v-hasPermi="['sys:company:check']" @click="checkJudge(scope.row)">审核</el-link>
          <el-divider direction="vertical" v-hasPermi="['sys:company:check']" v-if="scope.row.checkStatus < 2"/>
          <el-link type="info" v-if="scope.row.checkStatus == 2" @click="createQrcodeHandler(scope.row)">二维码</el-link>
          <el-divider direction="vertical"  v-if="scope.row.checkStatus == 2"/>
          <el-link type="primary" @click="handleAdd(scope.row)">编辑</el-link>
          <el-divider direction="vertical" />
          <el-link type="error" @click="handleDelete(scope.row)">删除</el-link>
         </template>
      </el-table-column>
    </el-table>
    <pagination v-show="queryParams.total > 0" :total="queryParams.total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
    <!-- 添加或修改对话框 -->
    <el-dialog :title="title" v-model="open" width="600px" append-to-body>
      <el-form ref="deptRef" :model="form" :rules="rules" label-width="140px">
        <el-form-item label="企业名称" prop="companyName">
          <el-input placeholder="请输入企业名称" v-model="form.companyName"></el-input>
        </el-form-item>
        <el-form-item label="联系人"  prop="companyUser">
          <el-input placeholder="请输入联系人" v-model="form.companyUser"></el-input>
        </el-form-item>
        <el-form-item label="手机号码" prop="companyPhone">
          <el-input  placeholder="请输入手机号码" v-model="form.companyPhone"></el-input>
        </el-form-item>
        <el-form-item label="来访人员" prop="comeUser">
          <el-input  placeholder="请输入" v-model="form.comeUser"></el-input>
        </el-form-item>
        <el-form-item label="来访事项" prop="comeContent">
          <el-input  placeholder="请输入" v-model="form.comeContent"></el-input>
        </el-form-item>
        <el-form-item label="随行人数" prop="userNum">
          <el-input  placeholder="请输入" v-model="form.userNum"></el-input>
        </el-form-item>
        <el-form-item label="备注">
          <el-input placeholder="请输入备注" v-model="form.remark"></el-input>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
    <exportExcelCom ref="exporttem" @resList="resList"></exportExcelCom>
    <exportRecord ref="exportRecordCom" :recordRow="recordRow" @uploadList="getList"></exportRecord>
    <judgeCom ref="judgeComRef" @upload="getList"></judgeCom>
    <createQrcode ref="createQrcodeRef"></createQrcode>
  </div>
</template>
<script setup name="Dept">
import FileUpload from '@/components/ImageUpload/index'
import exportRecord from './components/exportRecord'
import createQrcode from './components/createQrcode'
import judgeCom from './components/judge'
import { listCompanyLog,addCompany, updStatus, delCompanyLog, updCompanyLog } from "@/api/system/company/company";
import exportExcelCom from './components/export'
import { computed } from "vue";
import { judgeStatus, companyStatus, scopeList } from '@/utils/mapList/index.ts'
import useSettingsStore from "@/store/modules/settings";
const thcolor = computed(() => useSettingsStore().theme);
const { proxy } = getCurrentInstance();
const { sys_normal_disable } = proxy.useDict("sys_normal_disable");
const deptList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const title = ref("");
const deptOptions = ref([]);
const isExpandAll = ref(false);
const refreshTable = ref(true);
const exporttem = ref()
const exportRecordCom = ref()
const judgeComRef = ref()
const createQrcodeRef = ref()
const options = reactive({
  // -1拒绝,0待审批,1审批中,2通过
  checkOptions: [
    {
      label: '拒绝',
      value: -1
    },
    {
      label: '待审批',
      value: 0
    },
    {
      label: '审批中',
      value: 1
    },
    {
      label: '通过',
      value: 2
    }
  ],
  companyStatus: [
  {
      label: '正常',
      value: 0
    },
    {
      label: '禁用',
      value: 1
    },
  ],
  socreList: [
  {
      label: '导入',
      value: 1
    },
    {
      label: '注册',
      value: 0
    },
  ]
})
const data = reactive({
  form: {},
  queryParams: {
    deptName: undefined,
    status: undefined,
    deptType: undefined,
    pageNum: 1,
    pageSize: 10,
    total: 1
  },
  rules: {
    companyName: [{ required: true, message: "企业名称不能为空", trigger: "blur" }],
    companyUser: [{ required: true, message: "联系人不能为空", trigger: "blur" }],
    companyPhone: [{ required: true, message: "手机号码不能为空", trigger: "blur" }, {
      pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur"
    }],
    companyCode: [{ required: true, message: "统一社会信用代码不能为空", trigger: "blur" }],
    companyImg: [{ required: true, message: "营业执照不能为空", trigger: "blur" }],
    companyAddress: [{ required: true, message: "企业地址不能为空", trigger: "blur" }],
    // email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
    // phone: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: "请输入正确的手机号码", trigger: "blur" }],
  },
});
const { queryParams, form, rules } = toRefs(data);
// const dispDeptType = computed(() => (e) => {
//   return dept_type.value.find((f) => f.value == e).label;
// });
const recordRow = ref([])
/** 查询企业列表 */
function getList() {
  loading.value = true;
  listCompanyLog(queryParams.value).then((response) => {
    deptList.value = response.rows
    data.queryParams.total = response.total
    loading.value = false;
  });
}
/** 取消按钮 */
function cancel() {
  open.value = false;
  reset();
  getList();
}
/** 表单重置 */
function reset() {
  form.value = {
    deptId: undefined,
    parentId: undefined,
    deptName: undefined,
    orderNum: 0,
    leader: undefined,
    phone: undefined,
    email: undefined,
    status: "0",
    deptType: undefined,
  };
  proxy.resetForm("deptRef");
}
const queryRef = ref()
/** 搜索按钮操作 */
function handleQuery() {
  getList();
}
/** 重置按钮操作 */
function resetQuery() {
  queryRef.value.resetFields();
  handleQuery();
}
/** 新增按钮操作 */
function handleAdd(row) {
  if(row) {
    form.value = row
    title.value = "编辑企业";
  } else {
    form.value = {
      companyStatus: 0
    }
    title.value = "添加企业";
  }
  open.value = true;
}
/** 提交按钮 */
function submitForm() {
  proxy.$refs["deptRef"].validate((valid) => {
    if (valid) {
      if (form.value.companyId != undefined) {
        updCompanyLog(form.value).then((response) => {
          proxy.$modal.msgSuccess("修改成功");
          open.value = false;
          getList();
        });
      } else {
        addCompany(form.value).then((response) => {
          proxy.$modal.msgSuccess("新增成功");
          open.value = false;
          getList();
        });
      }
    }
  });
}
/** 删除按钮操作 */
function handleDelete(row) {
  proxy.$modal
    .confirm('是否确认删除该数据?')
    .then(function () {
      return delCompanyLog({delId: row.id});
    })
    .then(() => {
      getList();
      proxy.$modal.msgSuccess("删除成功");
    })
    .catch(() => {});
}
// 修改企业信息
function changeCompanyNews(row, event) {
  if(loading.value){
    return
  }
  updStatus(row).then(val => {
    proxy.$modal.msgSuccess("修改成功");
    getList();
  })
}
// 导入模板
function exportExcel() {
  exporttem.value.openDialog()
}
// 导入记录
function exportRecordComOpen() {
  exportRecordCom.value.openDialog()
}
function resList(row) {
  recordRow.value = row
  exportRecordCom.value.openDialog()
}
function checkJudge(row) {
  judgeComRef.value.openDialog(row)
}
function createQrcodeHandler(row) {
  createQrcodeRef.value.openDialog(row)
}
getList();
</script>
<style scoped lang="scss">
.evenly-distributed-labels {
  :deep(){
    .el-form-item__label {
      position: relative; /* 设置相对定位作为星号的定位基准 */
      text-align: justify;
      text-align-last: justify; /* 确保最后一行也两端对齐 */
      padding-left: 10px; /* 为星号预留空间 */
      display: inline-block;
    }
  }
}
</style>
src/views/main/components/selectColor.vue
New file
@@ -0,0 +1,91 @@
<template>
  <div class="select-color">
    <div class="color red" :class="[selectColor === '#FF0000' ? 'active' : '']" @click="selectColorClick('#FF0000')" />
    <div
      class="color green"
      :class="[selectColor === '#008000' ? 'active' : '']"
      @click="selectColorClick('#008000')"
    />
    <div
      class="color yellow"
      :class="[selectColor === '#0000FF' ? 'active' : '']"
      @click="selectColorClick('#0000FF')"
    />
    <div
      class="gradit-color"
      :style="{ 'background': `linear-gradient(${selectColor}, ${adjustColor(selectColor, 200)})` }"
    />
  </div>
</template>
<script>
export default {
  props: {
    selectColor: {
      type: String,
      default: '#FF0000'
    }
  },
  methods: {
    selectColorClick(item) {
      this.$emit('update:selectColor', item)
      this.$emit('changeRender')
    },
    adjustColor(color, range) {
      let newColor = '#'
      for (let i = 0; i < 3; i++) {
        const hxStr = color.substr(i * 2 + 1, 2)
        let val = parseInt(hxStr, 16)
        val += range
        if (val < 0) val = 0
        else if (val > 255) val = 255
        newColor += val.toString(16).padStart(2, '0')
      }
      this.$emit('minColor', newColor)
      return newColor
    }
  }
}
</script>
<style scoped>
.select-color {
  position: fixed;
  top: 0;
  z-index: 100000;
  padding: 20px;
}
.title {
  font-size: 26px;
  font-weight: 700;
  margin-bottom: 10px;
}
.color {
  width: 100px;
  height: 100px;
  margin-bottom: 20px;
}
.red {
  background-color: red;
}
.green {
  background-color: green;
}
.yellow {
  background-color: #0000FF;
}
.active {
  border: 2px solid #a0a0a0;
  box-shadow: 0 0 10px #232323;
}
.gradit-color {
  width: 10px;
  height: 200px;
  border-radius: 10px;
}
</style>
src/views/main/components/theme.vue
New file
@@ -0,0 +1,42 @@
<template>
  <div class="theme-box">
    <el-select v-model="style" @change="styleChange" size="large">
      <el-option v-for="(item, index) in styleOptions" :key="index" :label="item.label" :value="item.value" />
    </el-select>
  </div>
</template>
<script>
export default {
  data() {
    return {
      style: 'dark',
      styleOptions: [
        { label: '标准', value: 'normal' },
        { label: '幻影黑', value: 'dark' },
        { label: '月光银', value: 'light' },
        { label: '远山黛', value: 'whitesmoke' },
        { label: '草色青', value: 'fresh' },
        { label: '雅士灰', value: 'grey' },
        { label: '涂鸦', value: 'graffiti' },
        { label: '马卡龙', value: 'macaron' },
        { label: '靛青蓝', value: 'blue' },
        { label: '极夜蓝', value: 'darkblue' },
        { label: '酱籽', value: 'wine' }
      ]
    }
  },
  methods: {
    styleChange(e) {
      this.$emit('styleChange', e)
    }
  }
}
</script>
<style>
.theme-box{
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 1000;
}
</style>
src/views/main/indexMarge.vue
New file
@@ -0,0 +1,552 @@
<template>
  <el-container>
    <selectColor :select-color.sync="selectColor" :min-color="minColor" @changeRender="changeRender" />
    <themeCom @styleChange="changeStyle" />
    <el-main style="margin: 0px; padding: 0px">
      <div id="aMap" :style="{ height: windowHeight - 50 + 'px' }" />
    </el-main>
  </el-container>
</template>
<script>
const markerContent = `
<div class="custom-content-marker" onclick="showContent()">
    <img src="//a.amap.com/jsapi_demos/static/demo-center/icons/dir-via-marker.png">
    </div>`
import selectColor from './components/selectColor.vue'
import themeCom from './components/theme.vue'
export default {
  name: 'AMap',
  components: {
    selectColor,
    themeCom
  },
  data() {
    return {
      circleMarker: [],
      recordValue: [], // 记录绘制过的文字
      adcode: 410000, // 中心行政code
      currentCodeObj: '', // 中心行政code
      map: null, // 地图实例化
      districtExplorer: null, // 渲染行政区域实例化
      windowHeight: document.documentElement.clientHeight,
      selectColor: '#FF0000',
      minColor: '',
      provinceData: [
        {
          'name': '郑州市',
          'value': '8.99'
        },
        {
          'name': '开封市',
          'value': '22.84'
        },
        {
          'name': '洛阳市',
          'value': '48.96'
        },
        {
          'name': '平顶山市',
          'value': '79.49'
        },
        {
          'name': '安阳市',
          'value': '37.82'
        },
        {
          'name': '鹤壁市',
          'value': '27.55'
        },
        {
          'name': '新乡市',
          'value': '90.76'
        },
        {
          'name': '焦作市',
          'value': '72.26'
        },
        {
          'name': '濮阳市',
          'value': '14.03'
        },
        {
          'name': '许昌市',
          'value': '32.93'
        },
        {
          'name': '漯河市',
          'value': '57.85'
        },
        {
          'name': '三门峡市',
          'value': '85.35'
        },
        {
          'name': '南阳市',
          'value': '99.59'
        },
        {
          'name': '商丘市',
          'value': '45.33'
        },
        {
          'name': '信阳市',
          'value': '69.38'
        },
        {
          'name': '周口市',
          'value': '65.45'
        },
        {
          'name': '驻马店市',
          'value': '90.25'
        },
        {
          'name': '济源市',
          'value': '88.85'
        }
      ],
      style: 'dark',
      marker: [],
      infoWindow: [],
      // marker: [],
      regionData: {
        type: 'FeatureCollection',
        features: [
          {
            type: 'Feature',
            geometry: {
              type: 'Polygon',
              coordinates: [
                [
                  [113.576491, 34.744435],
                  [113.605331, 34.768129],
                  [113.712447, 34.74782],
                  [113.673995, 34.66823],
                  [113.601211, 34.687994],
                  [113.573745, 34.705495],
                  [113.570998, 34.725249]
                ]
              ]
            },
            properties: {}
          }
        ]
      }
    }
  },
  mounted() {
    const vm = this
    vm.loadMap()
  },
  methods: {
    changeStyle(e) {
      this.style = e
      this.loadMap()
    },
    changeRender() {
      this.loadMap()
    },
    loadMap() {
      const vm = this
      vm.map = new AMap.Map('aMap', {
        viewMode: '2D', // 默认使用 2D 模式,如果希望使用带有俯仰角的 3D 模式,请设置 viewMode: '3D'
        zoom: 11, // 初始化地图层级
        center: [113.681999, 34.762029], // 初始化地图中心点
        mapStyle: 'amap://styles/' + this.style
      })
      vm.fillCityOrTown()
    },
    //  加载河南省市县
    fillCityOrTown() {
      const vm = this
      AMapUI.loadUI(['geo/DistrictExplorer'], function(DistrictExplorer) {
        // 启动页面
        vm.initPage(DistrictExplorer)
      })
    },
    initPage(DistrictExplorer) {
      const vm = this
      // 创建一个实例
      vm.districtExplorer = new DistrictExplorer({
        eventSupport: true, // 打开事件支持
        map: vm.map // 关联的地图实例
      })
      // 配置点击事件
      vm.districtExplorer.on('featureClick', function(e, feature) {
        var props = feature.properties
        // 如果存在子节点
        vm.recordValue.map(item => {
          item.setMap(null)
        })
        vm.recordValue = []
        vm.circleMarker.map(item => {
          // item.setMap(null)
          vm.map.remove(item)
        })
        vm.circleMarker = []
        if (feature.properties.level === 'district') {
          setTimeout(() => {
            vm.drawMarker(feature.properties.center)
          }, 500)
          vm.initData()
        }
        // if (props.childrenNum > 0) {
        // 切换聚焦区域
        vm.switch2AreaNode(props.adcode)
        // }
      })
      // 外部区域被点击
      vm.districtExplorer.on('outsideClick', function(e) {
        vm.districtExplorer.locatePosition(e.originalEvent.lnglat, function(_error, routeFeatures) {
          vm.recordValue.map(item => {
            item.setMap(null)
          })
          vm.recordValue = []
          vm.infoWindow.forEach(element => {
            element.close(vm.map)
          })
          vm.marker.forEach(element => {
            element.setMap(null)
          })
          vm.circleMarker.map(item => {
            // item.setMap(null)
            vm.map.remove(item)
          })
          vm.circleMarker = []
          if (routeFeatures && routeFeatures.length > 1) {
            // 切换到省级区域
            vm.switch2AreaNode(routeFeatures[1].properties.adcode)
          } else {
            // 切换到全国
            vm.switch2AreaNode(100000)
          }
        }, {
          levelLimit: 2
        })
      })
      var adcode = vm.adcode // 全国的区划编码
      vm.districtExplorer.loadAreaNode(adcode, function(error, areaNode) {
        if (error) {
          console.error(error)
          return
        }
        // 绘制载入的区划节点
        vm.renderAreaNode(areaNode)
      })
    },
    initData(){
            for (let i = 0; i < this.regionData.features.length; i++) {
                let item = this.regionData.features[i];
                if(item.geometry.type=='Polygon'){
                    let arr = item.geometry.coordinates
                    let polygon = new AMap.Polygon({
                        path: arr,
                        fillColor: '#ccebc5',
                        strokeOpacity: 1,
                        fillOpacity: 0.2,//背景透明度
                        strokeColor: '#2b8cbe',
                        strokeWeight: 2,
                        strokeStyle: 'dashed',
                        strokeDasharray: [5, 5],
                    });
                    this.map.add(polygon);
                }
            }
        },
    getMathRandom() {
      return (Math.random() * 101).toFixed(2)
    },
    adjustColor(color, range) {
      let newColor = '#'
      for (let i = 0; i < 3; i++) {
        const hxStr = color.substr(i * 2 + 1, 2)
        let val = parseInt(hxStr, 16)
        val += range
        if (val < 0) val = 0
        else if (val > 255) val = 255
        newColor += val.toString(16).padStart(2, '0')
      }
      this.$emit('minColor', newColor)
      return newColor
    },
    renderAreaNode(areaNode) {
      const vm = this
      vm.map.setBounds(areaNode.getBounds(), null, null, true)
      // 清除已有的绘制内容
      vm.districtExplorer.clearFeaturePolygons()
      var colors = ['#3366cc', '#dc3912', '#ff9900', '#109618', '#990099', '#0099c6', '#dd4477', '#66aa00']
      // 绘制子区域
      // const arr = []
      vm.districtExplorer.renderSubFeatures(areaNode, function(feature, i) {
        // arr.push({
        //   name: feature.properties.name, value: vm.getMathRandom()
        // })
        // console.log(feature.adcode) // 行政区的areacode
        var fillColor = colors[i % colors.length]
        var strokeColor = colors[colors.length - 1 - i % colors.length]
        const value = vm.provinceData.find(item => item.name === feature.properties.name)
        const color = vm.adjustColor(vm.selectColor, 200)
        const colorValue = vm.getColorBetween(value.value, 0, 100, color, vm.selectColor)
        const fontStyle = {
          'background-color': 'rgba(0,0,0,0)',
          'border-width': 0,
          'font-size': '10px',
          color: '#fff',
          'text-align': 'center'
        }
        // 定义Text类
        const text1 = new AMap.Text({
          text: feature.properties.name,
          position: new AMap.LngLat(feature.properties.center[0], feature.properties.center[1]),
          style: fontStyle
        })
        // 创建圆形点标记 CircleMarker 实例
        const circleMarker = new AMap.CircleMarker({
          center: new AMap.LngLat(feature.properties.center[0], feature.properties.center[1]),
          radius: 4, // 3D视图下,CircleMarker半径不要超过64px
          strokeColor: 'white',
          strokeWeight: 2,
          strokeOpacity: 1,
          fillColor: 'green',
          fillOpacity: 1,
          zIndex: 100000,
          bubble: true,
          cursor: 'pointer',
          clickable: true
        })
        vm.recordValue.push(text1)
        vm.circleMarker.push(circleMarker)
        vm.map.add(text1)
        vm.map.add(circleMarker)
        return {
          cursor: 'default',
          bubble: true,
          strokeColor: strokeColor, // 线颜色
          strokeOpacity: 1, // 线透明度
          strokeWeight: 1, // 线宽
          fillColor: colorValue, // 填充色
          fillOpacity: 1 // 填充透明度
        }
      })
      // 绘制父区域
      vm.districtExplorer.renderParentFeature(areaNode, {
        cursor: 'default',
        bubble: true,
        strokeColor: 'black', // 线颜色
        strokeOpacity: 1, // 线透明度
        strokeWeight: 1, // 线宽
        fillColor: areaNode.getSubFeatures().length ? null : colors[0], // 填充色
        fillOpacity: 0.35 // 填充透明度
      })
      // vm.
      vm.map.setFitView(vm.districtExplorer.getAllFeaturePolygons())
    },
    // 刷新页面
    switch2AreaNode(adcode, callback) {
      const vm = this
      if (vm.currentCodeObj && ('' + vm.currentCodeObj.getAdcode() === '' + adcode)) {
        return
      }
      vm.loadAreaNode(adcode, function(error, areaNode) {
        if (error) {
          if (callback) {
            callback(error)
          }
          return
        }
        vm.adcode = window.currentAreaNode = areaNode.adcode
        vm.currentCodeObj = window.currentAreaNode = areaNode
        // 设置当前使用的定位用节点
        vm.districtExplorer.setAreaNodesForLocating([vm.currentCodeObj])
        vm.refreshAreaNode(areaNode)
        if (callback) {
          callback(null, areaNode)
        }
      })
    },
    // 刷新区域边界
    loadAreaNode(adcode, callback) {
      const vm = this
      vm.districtExplorer.loadAreaNode(adcode, function(error, areaNode) {
        if (error) {
          if (callback) {
            callback(error)
          }
          return
        }
        if (callback) {
          callback(null, areaNode)
        }
      })
    },
    refreshAreaNode(areaNode) {
      this.districtExplorer.setHoverFeature(null)
      this.renderAreaPolygons(areaNode)
    },
    // 绘制某个区域的边界
    renderAreaPolygons(areaNode) {
      const vm = this
      // 更新地图视野
      vm.map.setBounds(areaNode.getBounds(), null, null, true)
      // 清除已有的绘制内容
      vm.districtExplorer.clearFeaturePolygons()
      var colors = ['#3366cc', '#dc3912', '#ff9900', '#109618', '#990099', '#0099c6', '#dd4477', '#66aa00']
      // 绘制子区域
      vm.districtExplorer.renderSubFeatures(areaNode, function(feature, i) {
        var fillColor = colors[i % colors.length]
        var strokeColor = colors[colors.length - 1 - i % colors.length]
        const fontStyle = {
          'background-color': 'rgba(0,0,0,0)',
          'border-width': 0,
          'text-align': 'center',
          'font-size': '14px',
          color: '#fff'
        }
        const text1 = new AMap.Text({
          text: feature.properties.name,
          position: new AMap.LngLat(feature.properties.center[0], feature.properties.center[1]),
          style: fontStyle
        })
        vm.recordValue.push(text1)
        vm.map.add(text1)
        const value = vm.provinceData.find(item => item.name === feature.properties.name)
        if (value && value.value) {
          const color = vm.adjustColor(vm.selectColor, 200)
          fillColor = vm.getColorBetween(value.value, 0, 100, color, vm.selectColor)
        }
        // 创建圆形点标记 CircleMarker 实例
        const circleMarker = new AMap.CircleMarker({
          center: new AMap.LngLat(feature.properties.center[0], feature.properties.center[1]),
          radius: 4, // 3D视图下,CircleMarker半径不要超过64px
          strokeColor: 'white',
          strokeWeight: 2,
          strokeOpacity: 1,
          fillColor: 'green',
          fillOpacity: 1,
          zIndex: 100000,
          bubble: true,
          cursor: 'pointer',
          clickable: true
        })
        vm.circleMarker.push(circleMarker)
        vm.map.add(circleMarker)
        return {
          cursor: 'default',
          bubble: true,
          strokeColor: strokeColor, // 线颜色
          strokeOpacity: 1, // 线透明度
          strokeWeight: 1, // 线宽
          fillColor: fillColor, // 填充色
          fillOpacity: 1 // 填充透明度
        }
      })
      // 绘制父区域
      vm.districtExplorer.renderParentFeature(areaNode, {
        cursor: 'default',
        bubble: true,
        strokeColor: 'black', // 线颜色
        strokeOpacity: 1, // 线透明度
        strokeWeight: 1, // 线宽
        fillColor: areaNode.getSubFeatures().length ? null : colors[0], // 填充色
        fillOpacity: 0.35 // 填充透明度
      })
    },
    // 根据值返回颜色
    getColorBetween(value, minValue, maxValue, minColor, maxColor) {
      // 将颜色转换为RGB
      function hexToRgb(hex) {
        const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
        return result ? {
          r: parseInt(result[1], 16),
          g: parseInt(result[2], 16),
          b: parseInt(result[3], 16)
        } : null
      }
      // 将RGB转换为十六进制颜色
      function rgbToHex(r, g, b) {
        return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
      }
      // 将颜色的每个分量进行插值
      function interpolateColor(start, end, factor) {
        return Math.round(start + (end - start) * factor)
      }
      // 确保值在最小值和最大值之间
      value = Math.max(minValue, Math.min(value, maxValue))
      // 计算因子,将值范围映射到0到1之间
      const factor = (value - minValue) / (maxValue - minValue)
      // 获取两种颜色的RGB值
      const minRgb = hexToRgb(minColor)
      const maxRgb = hexToRgb(maxColor)
      // 根据因子插值RGB分量
      const r = interpolateColor(minRgb.r, maxRgb.r, factor)
      const g = interpolateColor(minRgb.g, maxRgb.g, factor)
      const b = interpolateColor(minRgb.b, maxRgb.b, factor)
      // 将RGB转换为十六进制颜色并返回
      return rgbToHex(r, g, b)
    },
    // 绘制标点
    // 绘制标点
    drawMarker(positionArg) {
      var content = [
        '<div><b>这是个提示文字</b>',
        '地址:郑州市金水区花园路</div>'
      ]
      const position = new AMap.LngLat(positionArg[0], positionArg[1]) // Marker 经纬度
      // 创建 infoWindow 实例
      function getImageUrl(url) {
        console.log(`../../assets/icon/${url}.png`)
        const path = new URL(`../../assets/icon/${url}.png`, import.meta.url)
        return path.href
      }
      for (let a = 0; a < 4; a++) {
        const icon = new AMap.Icon({
          size: new AMap.Size(20, 20), // 图标尺寸
          image: getImageUrl(`icon${a + 1}`), // 图标的URL
          imageSize: new AMap.Size(20, 20) // 图标所用图片的大小
        })
        const position = new AMap.LngLat(positionArg[0] - 0.02 * a, positionArg[1]) // Marker 经纬度
        const infoWindow = new AMap.InfoWindow({
          content: content.join('<br>'), // 传入字符串拼接的 DOM 元素
          anchor: 'top-center',
          position: position
        // offset: [10, 40]
        })
        this.infoWindow.push(infoWindow)
        const marker = new AMap.Marker({
          position: position,
          // content: markerContent, // 将 html 传给 content
          // icon: '',
          icon: icon,
          offset: new AMap.Pixel(-10, -30) // 以 icon 的 [center bottom] 为原点
        })
        this.map.add(marker)
        this.marker.push(marker)
        marker.on('click', () => {
          infoWindow.open(this.map)
        })
      }
    }
  }
}
</script>
<style scoped>
.aMap {
  width: 100vw;
  height: 100vh;
}
</style>