明树Git Lab

Commit d57c83ce authored by yangyajing's avatar yangyajing

投资目标责任书

parent c7b422a8
Pipeline #105876 passed with stage
in 16 seconds
...@@ -46,15 +46,6 @@ const { proxy } = getCurrentInstance(); ...@@ -46,15 +46,6 @@ const { proxy } = getCurrentInstance();
const router = useRouter(); const router = useRouter();
// 计算菜单路由
const menuRoutes = computed(() => {
const mainRoute = router.options.routes.find((route) => route.path === "/");
if (!mainRoute?.children) return [];
return mainRoute.children.filter(
(route) => !route.meta || route.meta.showInMenu !== false
);
});
// 获取资源库数据 // 获取资源库数据
const getResourceData = () => { const getResourceData = () => {
proxy.$post({ proxy.$post({
......
<template>
<div class="breadcrumb">
<el-breadcrumb separator="/">
<el-breadcrumb-item>
<router-link to="/homePage">首页</router-link>
</el-breadcrumb-item>
<el-breadcrumb-item v-for="item in breadcrumbList" :key="item.path">
<router-link :to="item.path">{{ item.title }}</router-link>
</el-breadcrumb-item>
</el-breadcrumb>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
const breadcrumbList = ref([])
// 生成面包屑数据
const generateBreadcrumb = matchedRoutes => {
return matchedRoutes
.filter(route => route.meta?.menuName && route.path !== '/homePage')
.map(route => ({
path: route.path,
title: route.meta?.menuName || route.name || '未知页面'
}))
}
watch(
() => route.matched,
newVal => {
breadcrumbList.value = generateBreadcrumb(newVal)
},
{ immediate: true }
)
</script>
<style scoped lang="less">
.breadcrumb {
margin-bottom: 16px;
padding: 8px 0;
border-radius: 4px;
}
</style>
import { createRouter, createWebHashHistory } from 'vue-router' import { createRouter, createWebHashHistory } from 'vue-router'
import MainLayout from '@/layouts/MainLayout.vue'
import { useUserStore } from "@/stores/user.js"; import { useUserStore } from "@/stores/user.js";
import { routes } from "./routes.js"
const routes = [
{
path: '/login',
name: 'login',
component: () => import('@/views/login/index.vue'),
meta: { nopermission: true }
},
{
path: '/gzbPage',
name: 'gzbPage',
title: '数据大屏',
component: () => import('@/views/homePage/index.vue'),
meta: { menuName: '数据大屏', icon: 'platform', nopermission: true }
},
{
path: '/',
name: '首页',
redirect: '/homePage',
component: MainLayout,
children: [
{
path: '/homePage',
name: 'dataSummary',
title: '数据大屏',
component: () => import('@/views/homePage/index.vue'),
meta: { menuName: '数据大屏', icon: 'platform' }
},
{
path: '/projectManage',
name: 'projectManage',
title: '项目管理',
meta: { menuName: '项目管理', icon: 'Management' },
redirect: "/projectAllPage",
children: [
{
path: '/projectDraft',
name: 'projectDraft',
title: '项目遴选',
component: () => import('@/views/managePage/projectDraft.vue'),
meta: { menuName: '项目遴选' }
},
{
path: '/projectSetUp',
name: 'projectSetUp',
title: '项目立项',
component: () => import('@/views/managePage/projectSetUp.vue'),
meta: {
menuName: '项目立项'
}
},
{
path: '/projectArgument',
name: 'projectArgument',
title: '项目论证',
component: () => import('@/views/managePage/projectArgument.vue'),
meta: {
menuName: '项目论证'
}
},
{
path: '/projectDecision',
name: 'projectDecision',
title: '项目决策',
component: () => import('@/views/managePage/projectDecision.vue'),
meta: {
menuName: '项目决策'
}
},
{
path: '/projectAllPage',
name: 'projectAllPage',
title: '项目档案库',
component: () => import('@/views/managePage/projectAllPage.vue'),
meta: { menuName: '项目档案库' }
},
{
path: '/addProject/:type',
name: 'addProject',
title: '新增项目',
component: () => import('@/views/managePage/addProject.vue'),
meta: {
menuName: '新增项目',
showInMenu: false // 不在菜单中显示
}
}
]
},
{
path: '/templateManage',
name: 'templateManage',
title: '模板管理',
component: () => import('@/views/managePage/templateManage.vue'),
meta: { menuName: '模板管理', icon: 'Management' }
},
{
path: '/systemManage',
name: '系统管理',
title: 'systemManage',
meta: { menuName: '系统管理', icon: 'tools' },
children: [
{
path: '/systemManage/departManage',
name: '部门管理',
title: 'departManage',
component: () => import('@/views/systemManage/departManage.vue'),
meta: { menuName: '部门管理',}
},
{
path: '/systemManage/userManage',
name: '用户管理',
title: 'userManage',
component: () => import('@/views/systemManage/userManage.vue'),
meta: { menuName: '用户管理',}
},
{
path: '/systemManage/roleManage',
name: '角色管理',
title: 'roleManage',
component: () => import('@/views/systemManage/roleManage.vue'),
meta: { menuName: '角色管理',}
},
{
path: '/systemManage/menuManage',
name: '菜单管理',
title: 'menuManage',
component: () => import('@/views/systemManage/menuManage.vue'),
meta: { menuName: '菜单管理',}
}
]
},
{
path: "/building",
name: "building",
title: "建设中",
component: () => import("@/views/homePage/building.vue")
}
]
}
]
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
routes routes
......
import MainLayout from '@/layouts/MainLayout.vue'
const routes = [
{
path: '/login',
name: 'login',
component: () => import('@/views/login/index.vue'),
meta: { nopermission: true }
},
{
path: '/gzbPage',
name: 'gzbPage',
title: '数据大屏',
component: () => import('@/views/homePage/index.vue'),
meta: { nopermission: true }
},
{
path: '/',
name: '首页',
redirect: '/homePage',
component: MainLayout,
children: [
{
path: '/homePage',
name: 'dataSummary',
title: '数据大屏',
component: () => import('@/views/homePage/index.vue')
},
{
path: '/projectManage',
name: 'projectManage',
title: '投前管理',
redirect: "/projectAllPage",
children: [
{
path: '/projectDraft',
name: 'projectDraft',
title: '项目遴选',
component: () => import('@/views/managePage/projectDraft.vue')
},
{
path: '/projectSetUp',
name: 'projectSetUp',
title: '项目立项',
component: () => import('@/views/managePage/projectSetUp.vue')
},
{
path: '/projectArgument',
name: 'projectArgument',
title: '项目论证',
component: () => import('@/views/managePage/projectArgument.vue')
},
{
path: '/projectDecision',
name: 'projectDecision',
title: '项目决策',
component: () => import('@/views/managePage/projectDecision.vue')
},
{
path: '/projectAllPage',
name: 'projectAllPage',
title: '项目档案库',
component: () => import('@/views/managePage/projectAllPage.vue')
},
{
path: '/addProject/:type',
name: 'addProject',
title: '新增项目',
component: () => import('@/views/managePage/addProject.vue')
}
]
},
{
path: "/investingManage",
name: "investingManage",
title: "投中管理",
redirect: "/targetLiabilityStatement",
children: [
{
path: "/targetLiabilityStatement",
name: "targetLiabilityStatement",
title: "投资目标责任书",
component: () => import('@/views/investingManage/targetLiabilityStatement.vue')
},
{
path: '/addStatement',
name: 'addStatement',
title: '新增责任书',
component: () => import('@/views/investingManage/addStatement.vue')
}
]
},
{
path: '/templateManage',
name: 'templateManage',
title: '模板管理',
component: () => import('@/views/managePage/templateManage.vue')
},
{
path: '/systemManage',
name: '系统管理',
title: 'systemManage',
meta: { menuName: '系统管理' },
children: [
{
path: 'departManage',
name: '部门管理',
title: 'departManage',
component: () => import('@/views/systemManage/departManage.vue')
},
{
path: 'userManage',
name: '用户管理',
title: 'userManage',
component: () => import('@/views/systemManage/userManage.vue')
},
{
path: 'roleManage',
name: '角色管理',
title: 'roleManage',
component: () => import('@/views/systemManage/roleManage.vue')
},
{
path: 'menuManage',
name: '菜单管理',
title: 'menuManage',
component: () => import('@/views/systemManage/menuManage.vue')
}
]
},
{
path: "/building",
name: "building",
title: "建设中",
component: () => import("@/views/homePage/building.vue")
}
]
}
];
export {
routes
};
\ No newline at end of file
...@@ -86,4 +86,115 @@ ...@@ -86,4 +86,115 @@
} }
} }
} }
}
.add-project{
&-container{
width: 100%;
height: 100%;
padding: 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
.el-collapse-item__header{
color: var(--el-color-primary);
}
}
&-header{
display: flex;
justify-content: space-between;
}
&-content{
flex: 1;
height: 0;
display: flex;
flex-direction: column;
.tabs-content{
flex: 1;
max-height: 100%;
}
.el-tabs{
height: 100%;
}
.el-tab-pane{
height: 100%;
.tab-content{
height: 100%;
overflow: auto;
padding: 0 20px;
.col-title{
height: 24px;
line-height: 24px;
font-weight: bold;
text-align: center;
}
.tab-handle{
margin: 10px 0;
display: flex;
justify-content: flex-end;
}
.el-table{
margin-bottom: 10px;
thead {
color: #000;
th{
background: #f5f7fa;
.cell{
text-align: center;
}
}
}
.sums-column{
display: flex;
flex-direction: column;
justify-content: flex-start;
&>div{
height: 26px;
line-height: 26px;
text-align: center;
}
}
}
.upload-file-wrap{
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.file-name{
flex: 1;
width: 0;
color: #409eff;
cursor: pointer;
-webkit-background-clip: text;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.delete-btn{
cursor: pointer;
color: #F56C6C;
}
}
.el-select__wrapper{
.el-select__selection.is-near{
max-height: 120px;
overflow: auto;
}
}
}
.always-click{
padding: 2px;
font-size: 12px;
cursor: pointer !important;
color: var(--el-color-primary);
font-weight: 500;
font-family: Arial, sans-serif;
display: inline-flex;
align-items: center;
}
}
.project-tab-content{
padding: 0 20px;
height: 100%;
}
}
} }
\ No newline at end of file
<template>
<div class="form-demo">
<h2>可配置表单组件示例</h2>
<!-- 基础表单示例 -->
<el-card class="demo-card" header="基础表单">
<config-form
v-model="basicForm"
:config="basicConfig"
:items="basicItems"
:rules="basicRules"
@submit="handleBasicSubmit"
@reset="handleBasicReset"
/>
</el-card>
<!-- 复杂表单示例 -->
<el-card class="demo-card" header="复杂表单">
<config-form
v-model="complexForm"
:config="complexConfig"
:items="complexItems"
:rules="complexRules"
@submit="handleComplexSubmit"
@reset="handleComplexReset"
@change="handleComplexChange"
/>
</el-card>
<!-- 树形选择器示例 -->
<el-card class="demo-card" header="树形选择器">
<config-form
v-model="treeForm"
:config="treeConfig"
:items="treeItems"
@submit="handleTreeSubmit"
@node-click="handleNodeClick"
@check="handleTreeCheck"
/>
</el-card>
<!-- 自定义表单示例 -->
<el-card class="demo-card" header="自定义表单">
<config-form
v-model="customForm"
:config="customConfig"
:items="customItems"
@submit="handleCustomSubmit"
>
<template #customSlot="{ item, value, onChange }">
<el-input
:model-value="value"
placeholder="这是一个自定义插槽"
@input="onChange"
>
<template #append>
<el-button @click="handleCustomAction(item)">自定义操作</el-button>
</template>
</el-input>
</template>
</config-form>
</el-card>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import ConfigForm from '../ConfigForm.vue'
// 基础表单数据
const basicForm = ref({
name: '',
age: null,
gender: '',
email: '',
description: ''
})
// 基础表单配置
const basicConfig = {
labelWidth: '100px',
showButtons: true,
submitText: '保存',
resetText: '清空'
}
// 基础表单项配置
const basicItems = [
{
type: 'input',
prop: 'name',
label: '姓名',
placeholder: '请输入姓名',
clearable: true,
rules: [
{ required: true, message: '请输入姓名', trigger: 'blur' },
{ min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' }
]
},
{
type: 'number',
prop: 'age',
label: '年龄',
min: 1,
max: 120,
rules: [
{ required: true, message: '请输入年龄', trigger: 'blur' },
{ type: 'number', message: '年龄必须为数字', trigger: 'blur' }
]
},
{
type: 'radio',
prop: 'gender',
label: '性别',
required: true,
options: [
{ label: '男', value: 'male' },
{ label: '女', value: 'female' }
]
},
{
type: 'input',
prop: 'email',
label: '邮箱',
placeholder: '请输入邮箱地址',
rules: [
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
]
},
{
type: 'textarea',
prop: 'description',
label: '个人简介',
placeholder: '请输入个人简介',
rows: 3,
maxlength: 200,
showWordLimit: true
}
]
// 基础表单验证规则
const basicRules = {}
// 复杂表单数据
const complexForm = ref({
userInfo: {
name: '',
department: ''
},
skills: [],
level: 3,
isActive: true,
birthDate: '',
workTime: '',
avatar: '',
color: '#409EFF',
range: [20, 80]
})
// 复杂表单配置
const complexConfig = {
labelWidth: '120px',
gutter: 20,
showButtons: true,
submitText: '提交',
resetText: '重置',
customButtons: [
{
key: 'preview',
text: '预览',
type: 'info',
handler: handlePreview
}
]
}
// 复杂表单项配置
const complexItems = [
{
type: 'input',
prop: 'userInfo.name',
label: '姓名',
placeholder: '请输入姓名',
span: 12,
prefix: 'User'
},
{
type: 'select',
prop: 'userInfo.department',
label: '部门',
placeholder: '请选择部门',
span: 12,
clearable: true,
options: [
{ label: '技术部', value: 'tech' },
{ label: '产品部', value: 'product' },
{ label: '设计部', value: 'design' },
{ label: '运营部', value: 'operation' }
]
},
{
type: 'checkbox',
prop: 'skills',
label: '技能',
span: 12,
options: [
{ label: 'JavaScript', value: 'js' },
{ label: 'Vue.js', value: 'vue' },
{ label: 'React', value: 'react' },
{ label: 'Node.js', value: 'node' },
{ label: 'Python', value: 'python' }
]
},
{
type: 'rate',
prop: 'level',
label: '熟练度',
span: 12,
showText: true,
texts: ['新手', '初级', '中级', '高级', '专家']
},
{
type: 'switch',
prop: 'isActive',
label: '状态',
span: 8,
activeText: '激活',
inactiveText: '禁用'
},
{
type: 'date',
prop: 'birthDate',
label: '出生日期',
span: 8,
valueFormat: 'YYYY-MM-DD'
},
{
type: 'time',
prop: 'workTime',
label: '工作时间',
span: 8,
valueFormat: 'HH:mm:ss'
},
{
type: 'upload',
prop: 'avatar',
label: '头像',
span: 12,
action: '/api/upload',
accept: 'image/*',
tip: '只能上传jpg/png文件,且不超过500kb'
},
{
type: 'color',
prop: 'color',
label: '主题色',
span: 12,
showAlpha: true
},
{
type: 'slider',
prop: 'range',
label: '范围',
span: 24,
range: true,
min: 0,
max: 100,
showStops: true
}
]
// 复杂表单验证规则
const complexRules = {
'userInfo.name': [
{ required: true, message: '请输入姓名', trigger: 'blur' }
],
'userInfo.department': [
{ required: true, message: '请选择部门', trigger: 'change' }
],
skills: [
{ type: 'array', required: true, message: '请至少选择一项技能', trigger: 'change' }
]
}
// 树形选择器数据
const treeForm = ref({
department: '',
departments: [],
category: ''
})
// 部门树形数据
const departmentData = [
{
value: '1',
label: '总公司',
children: [
{
value: '1-1',
label: '技术中心',
children: [
{ value: '1-1-1', label: '前端开发部' },
{ value: '1-1-2', label: '后端开发部' },
{ value: '1-1-3', label: '测试部' }
]
},
{
value: '1-2',
label: '产品中心',
children: [
{ value: '1-2-1', label: '产品设计部' },
{ value: '1-2-2', label: '用户研究部' }
]
},
{
value: '1-3',
label: '运营中心',
children: [
{ value: '1-3-1', label: '市场推广部' },
{ value: '1-3-2', label: '客户服务部' }
]
}
]
},
{
value: '2',
label: '分公司A',
children: [
{ value: '2-1', label: '技术部' },
{ value: '2-2', label: '销售部' }
]
}
]
// 分类数据
const categoryData = [
{
value: 'electronics',
label: '电子产品',
children: [
{
value: 'phones',
label: '手机',
children: [
{ value: 'iphone', label: 'iPhone' },
{ value: 'android', label: 'Android手机' },
{ value: 'huawei', label: '华为手机' }
]
},
{
value: 'computers',
label: '电脑',
children: [
{ value: 'laptop', label: '笔记本电脑' },
{ value: 'desktop', label: '台式电脑' },
{ value: 'tablet', label: '平板电脑' }
]
}
]
},
{
value: 'clothing',
label: '服装',
children: [
{ value: 'mens', label: '男装' },
{ value: 'womens', label: '女装' },
{ value: 'kids', label: '童装' }
]
}
]
// 自定义表单数据
const customForm = ref({
customField: '',
status: 'pending'
})
// 树形选择器配置
const treeConfig = {
labelWidth: '120px',
showButtons: true,
submitText: '保存',
resetText: '重置'
}
// 树形选择器表单项配置
const treeItems = [
{
type: 'tree',
prop: 'department',
label: '所属部门',
placeholder: '请选择部门',
data: departmentData,
clearable: true,
filterable: true,
checkStrictly: true,
renderAfterExpand: false,
span: 12
},
{
type: 'tree',
prop: 'departments',
label: '多选部门',
placeholder: '请选择多个部门',
data: departmentData,
clearable: true,
filterable: true,
showCheckbox: true,
multiple: true,
collapseTags: true,
maxCollapseTags: 3,
span: 12
},
{
type: 'tree',
prop: 'category',
label: '商品分类',
placeholder: '请选择分类',
data: categoryData,
clearable: true,
filterable: true,
checkStrictly: true,
defaultExpandAll: true,
span: 24
}
]
// 自定义表单配置
const customConfig = {
labelWidth: '100px',
inline: true
}
// 自定义表单项配置
const customItems = [
{
type: 'slot',
prop: 'customField',
label: '自定义字段',
slotName: 'customSlot'
},
{
type: 'select',
prop: 'status',
label: '状态',
options: [
{ label: '待处理', value: 'pending' },
{ label: '处理中', value: 'processing' },
{ label: '已完成', value: 'completed' }
]
}
]
// 事件处理函数
const handleBasicSubmit = (formData) => {
console.log('基础表单提交:', formData)
ElMessage.success('基础表单提交成功')
}
const handleBasicReset = () => {
ElMessage.info('基础表单已重置')
}
const handleComplexSubmit = (formData) => {
console.log('复杂表单提交:', formData)
ElMessage.success('复杂表单提交成功')
}
const handleComplexReset = () => {
ElMessage.info('复杂表单已重置')
}
const handleComplexChange = (formData) => {
console.log('复杂表单数据变化:', formData)
}
const handleCustomSubmit = (formData) => {
console.log('自定义表单提交:', formData)
ElMessage.success('自定义表单提交成功')
}
const handleCustomAction = (item) => {
console.log('自定义操作:', item)
ElMessage.info('执行自定义操作')
}
const handleTreeSubmit = (formData) => {
console.log('树形表单提交:', formData)
ElMessage.success('树形表单提交成功')
}
const handleNodeClick = (prop, data) => {
console.log('节点点击:', prop, data)
ElMessage.info(`点击了节点: ${data.label}`)
}
const handleTreeCheck = (prop, data) => {
console.log('节点选择:', prop, data)
ElMessage.info(`选择了节点: ${data.checkedNodes?.map(n => n.label).join(', ')}`)
}
const handlePreview = () => {
console.log('预览数据:', complexForm.value)
ElMessage.info('预览功能')
}
</script>
<style lang="less" scoped>
.form-demo {
padding: 20px;
h2 {
margin-bottom: 20px;
color: #333;
}
.demo-card {
margin-bottom: 20px;
:deep(.el-card__header) {
background-color: #f5f7fa;
font-weight: 600;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="map-container">
<div id="container"></div>
<!-- 加载动画层 -->
<div class="loading-overlay" v-if="showLoading">
<div class="loading-dot"></div>
</div>
</div>
</template>
<style scoped>
.map-container {
position: relative;
width: 100%;
height: 100%;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
/* background-color: rgba(252, 251, 251, 0); */
display: flex;
justify-content: center;
align-items: center;
z-index: 9999; /* 确保在地图上方显示 */
}
.loading-dot {
width: 30px;
height: 30px;
background-color: #00ddeb;
border-radius: 50%;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.5);
opacity: 0.7;
}
100% {
transform: scale(1);
opacity: 1;
}
}
</style>
<script setup>
import AMapLoader from "@amap/amap-jsapi-loader";
import {
nextTick,
onMounted,
reactive,
ref,
onUnmounted,
onActivated,
} from "vue";
import gansuLine from "./newLine.json";
let map = null;
// 控制加载动画显示状态
const showLoading = ref(true);
window._AMapSecurityConfig = {
securityJsCode: "75a8291a9e8f7c838fc5e4dd0d538f30",
// securityJsCode: "7aee6d6553ba9a8178e0c57b60a51481",
};
// 初始化地图
const handleInitMap = () => {
// 先显示遮罩层,延迟3秒后再加载地图
setTimeout(() => {
let selectName = sessionStorage.getItem("selectedContentBtn");
// 获取地图容器并设置初始样式
const container = document.getElementById("container");
if (container) {
container.style.opacity = "0"; // 初始设置为透明
container.style.transition = "opacity 0.5s ease-in-out"; // 添加过渡效果
}
AMapLoader.load({
key: "c691971f068b92c897fb908c4ddef6d4", // 申请好的Web端开发者Key
// key: "9a22433229a51dc5114d4bbf92f687ee", // 申请好的Web端开发者Key
version: "2.0",
plugins: ["AMap.DistrictSearch", "AMap.GeoJSON"],
})
.then((AMap) => {
map = new AMap.Map("container", {
//设置地图容器id
viewMode: "2D",
zoom: 4, //根据屏幕宽度设置初始化地图级别
center: [100.808299, 35.791787], //初始化地图中心点位置
expandZoomRange: true, // 开启显示范围设置
mapStyle: "amap://styles/2d017848d08f94f20b6e50aaae661148",
// mapStyle: "amap://styles/d9cd35cfbd75e272e528a7fde0bcfc53",
rotateEnable: false, // 是否可以旋转
copyrightControl: false,
logoControl: false,
});
// 监听地图加载完成事件
map.on("complete", function () {
// 执行地图相关操作
handleDistrict();
addPolylines();
handleAddMarket(selectName);
// 隐藏加载动画
showLoading.value = false;
// 显示地图,添加过渡效果
if (container) {
setTimeout(() => {
container.style.opacity = "1";
}, 100);
}
});
})
.catch((e) => {
console.error(e);
// 加载失败时也隐藏加载动画
showLoading.value = false;
// 显示地图容器
if (container) {
container.style.opacity = "1";
}
});
}, 3000);
};
// 高亮和描边
const handleDistrict = () => {
let districtSearch = new AMap.DistrictSearch({
subdistrict: 0, //获取边界不需要返回下级行政区
extensions: "all", //返回行政区边界坐标组等具体信息
level: "province", //查询行政级别为 市 province-省 district-市
});
let polygons = [];
districtSearch.search("中华人民共和国", function (status, result) {
map.remove(polygons); //清除上次结果
let bounds = result.districtList[0].boundaries;
// 描边
for (let i = 0; i < bounds.length; i++) {
let outerPolyline = new AMap.Polyline({
path: bounds[i],
strokeColor: "#72A8FF",
strokeWeight: 3,
map: map,
});
map.add(outerPolyline);
}
map.add(polygons);
map.setFitView(polygons); //视口自适应
});
};
// 添加新路线
const addPolylines = () => {
let geojsonObj = new AMap.GeoJSON({
geoJSON: gansuLine,
getPolyline: function (geojson, lnglats) {
// 生成路线
let polylineObj = new AMap.Polyline({
path: lnglats,
strokeWeight: 4,
strokeColor: "#F0E82A",
extData: geojson.properties, // 自定义属性数据
});
// 生成新的路线,用于覆盖旧的
const newPolyline = new AMap.Polyline({
path: lnglats,
strokeWeight: 4,
strokeColor: "#00DDEB",
isOutline: true,
borderWeight: 2,
outlineColor: "rgba(0, 221, 235, 1)",
cursor: "pointer",
});
map.add(newPolyline);
newPolyline.hide();
// 获取路线数据
const properties = polylineObj.getExtData();
// 填报内容
let content = `
<div class="infoWindow-title">项目OOI</div>
<div class="infoWindow-content">
<p>
<span class="infoWindow-content-title">数据01:</span>
<span class="infoWindow-content-value">${properties.amount}<span class="infoWindow-unit">单位</span></span>
</p>
<p>
<span class="infoWindow-content-title">数据02:</span>
<span class="infoWindow-content-value">${properties.amount}<span class="infoWindow-unit">单位</span></span>
</p>
<p>
<span class="infoWindow-content-title">数据03:</span>
<span class="infoWindow-content-value">${properties.amount}<span class="infoWindow-unit">单位</span></span>
</p>
</div>
<div class="infoWindow-bottom"></div>
`;
// 创建 infoWindow 实例
let infoWindow = new AMap.InfoWindow({
isCustom: true, // 使用自定义窗体
autoMove: true, // 是否自动调整窗体到视野内
closeWhenClickMap: true, // 控制是否在鼠标点击地图后关闭信息窗体
content: content, // 传入 dom 对象,或者 html 字符串
offset: new AMap.Pixel(120, 100),
});
// 鼠标经过
polylineObj.on("mouseover", function (e) {
newPolyline.show();
infoWindow.open(map, [`${e.lnglat.getLng()}`, `${e.lnglat.getLat()}`]);
});
// 鼠标移出
polylineObj.on("mouseout", function (e) {
newPolyline.hide();
infoWindow.close();
});
// 鼠标双击
polylineObj.on("dblclick", function (e) {});
return polylineObj;
},
});
map.add(geojsonObj);
};
// 添加标记
let currentMarkers = []; // 存储当前显示的标记
const handleAddMarket = (selectName) => {
// 清除之前的所有标记
if (currentMarkers.length > 0) {
map.remove(currentMarkers);
currentMarkers = [];
}
// 额外确保清除所有标记(防止其他地方创建的标记)
if (map) {
map.getAllOverlays("marker").forEach((marker) => {
map.remove(marker);
});
}
// 根据不同状态定义标记数据
const markerData = {
建设: [
// 安徽
{ number: 1, position: [117.27, 31.86], province: "安徽省" },
// 广东
{ number: 1, position: [113.2644, 23.1291], province: "广东省" },
// 陕西
{ number: 2, position: [108.948, 34.2632], province: "陕西省" },
// 广西
{ number: 2, position: [108.32, 22.824], province: "广西壮族自治区" },
// 山东
{ number: 2, position: [117.0009, 36.6758], province: "山东省" },
// 河北
{ number: 1, position: [114.5025, 38.0455], province: "河北省" },
],
试运营: [
// 四川
{ number: 2, position: [104.066, 30.5728], province: "四川省" },
// 山东
{ number: 3, position: [117.0009, 36.6758], province: "山东省" },
// 云南
{ number: 1, position: [102.7123, 25.0406], province: "云南省" },
// 陕西
{ number: 3, position: [108.948, 34.2632], province: "陕西省" },
// 广西
{ number: 1, position: [108.32, 22.824], province: "广西壮族自治区" },
// 湖北
{ number: 1, position: [114.2986, 30.5844], province: "湖北省" },
],
运营: [
// 四川
{ number: 1, position: [104.066, 30.5728], province: "四川省" },
// 山东
{ number: 1, position: [117.0009, 36.6758], province: "山东省" },
// 湖北
{ number: 1, position: [114.2986, 30.5844], province: "湖北省" },
],
退出: [
// 河南
{ number: 3, position: [113.6654, 34.757], province: "河南省" },
],
// 立项: [],
};
const positionsList = markerData[selectName] || [];
// 如果是"立项"或者没有数据,直接返回,不创建任何标记
if (!positionsList || positionsList.length === 0) {
return;
}
// 创建新的标记
for (var i = 0; i < positionsList.length; i++) {
const markerData = positionsList[i];
// 创建悬浮窗口内容
const infoContent = `
<div class="marker-info-window">
<div class="marker-info-title">${markerData.province}</div>
<div class="marker-info-content">
<span class="marker-info-label">路线数量:</span>
<span class="marker-info-value">${markerData.number}</span>
<span class="marker-info-unit">条</span>
</div>
</div>
`;
// 创建信息窗口实例
const infoWindow = new AMap.InfoWindow({
isCustom: true,
content: infoContent,
offset: new AMap.Pixel(0, -35),
closeWhenClickMap: true,
});
const marker = new AMap.Marker({
map: map,
position: markerData.position,
offset: new AMap.Pixel(-13, -30),
content:
'<div class="custom-content-marker">' +
'<img src="//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png" style="width: 40px;height: 40px;">' +
`<div class="anchorPoint">${markerData.number}</div>` +
"</div>",
});
// 鼠标悬浮事件
marker.on("mouseover", function (e) {
infoWindow.open(map, e.lnglat);
});
// 鼠标移出事件
marker.on("mouseout", function () {
infoWindow.close();
});
currentMarkers.push(marker);
}
};
// 暴露更新标记的方法给父组件
const updateMarkers = (selectName) => {
handleAddMarket(selectName);
};
// 重置地图到初始状态
const resetMap = () => {
if (map) {
map.setZoom(4);
map.setCenter([100.808299, 35.791787]);
}
};
// 暴露方法给父组件
defineExpose({
updateMarkers,
resetMap,
});
onMounted(() => {
handleInitMap();
// 监听窗口大小变化
window.addEventListener("resize", handleResize);
});
// 处理窗口大小变化
const handleResize = () => {
if (map) {
map.resize();
}
};
// 组件卸载时移除事件监听
onUnmounted(() => {
window.removeEventListener("resize", handleResize);
});
// 组件从keep-alive缓存中激活时触发
onActivated(() => {
// 确保地图容器已经渲染完成
nextTick(() => {
// 获取地图容器元素
const container = document.getElementById("container");
// 如果容器存在,设置明确的尺寸和初始样式
if (container) {
container.style.width = "100%";
container.style.height = "100%";
container.style.opacity = "0"; // 初始设置为透明
container.style.transition = "opacity 0.5s ease-in-out"; // 添加过渡效果
}
// 无论地图实例是否存在,都重新显示遮罩层并延迟加载地图
showLoading.value = true;
// 清除之前可能存在的定时器
if (window.mapTimer) {
clearTimeout(window.mapTimer);
}
// 延迟300毫秒后重新初始化地图
window.mapTimer = setTimeout(() => {
// 如果地图实例已存在,先清除它
if (map) {
map.destroy();
map = null;
}
// 重新初始化地图
handleInitMap();
}, 300);
});
});
</script>
<style scoped lang="less">
.tourism {
width: 100%;
height: 100%;
}
#container {
width: 100%;
height: 100%;
}
.custom-content-marker {
position: relative;
width: 25px;
height: 34px;
}
:deep(.infoWindow-title) {
background-image: url("../assets/images/标题.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
width: 299px;
line-height: 56px;
padding-left: 10px;
font-weight: 700;
}
:deep(.infoWindow-content) {
background-image: url("../assets/images/信息文本.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
width: 299px;
height: 100x;
padding-left: 10px;
padding-top: 5px;
padding-bottom: 5px;
}
:deep(.infoWindow-bottom) {
background-image: url("../assets/images/下标.png");
background-size: 100% 100%;
background-repeat: no-repeat;
background-position: center;
margin-top: 1px;
height: 22px;
}
:deep(.infoWindow-content-title) {
font-size: 18px;
color: #fff;
font-weight: 400;
}
:deep(.infoWindow-content-value) {
font-weight: 400;
font-size: 24px;
color: #93d2ff;
}
:deep(.infoWindow-unit) {
font-size: 20px;
color: #93d2ff;
display: inline-block;
margin-left: 3px;
}
:deep(.anchorPoint) {
position: absolute;
color: #fff;
position: absolute;
top: 30%;
left: 50%;
transform: translate(-50%, -50%);
}
// 标记悬浮窗口样式
:deep(.marker-info-window) {
background: #04427e;
border: 1px solid #00ddeb;
border-radius: 6px;
padding: 8px 12px;
box-shadow: 0 2px 8px rgba(0, 221, 235, 0.3);
backdrop-filter: blur(4px);
min-width: 120px;
}
:deep(.marker-info-title) {
font-size: 14px;
font-weight: 600;
color: #fff;
margin-bottom: 4px;
border-bottom: 1px solid rgba(0, 221, 235, 0.3);
padding-bottom: 2px;
}
:deep(.marker-info-content) {
display: flex;
align-items: center;
gap: 4px;
}
:deep(.marker-info-label) {
font-size: 12px;
color: #93d2ff;
font-weight: 400;
}
:deep(.marker-info-value) {
font-size: 16px;
font-weight: 600;
color: #00ddeb;
}
:deep(.marker-info-unit) {
font-size: 12px;
color: #93d2ff;
margin-left: 2px;
}
.amap-container {
background: none;
}
:deep(.amap-logo) {
display: none;
opacity: 0 !important;
}
:deep(.amap-copyright) {
opacity: 0;
}
</style>
<template>
<div class="add-project-container">
<div class="add-project-content" v-loading="loading">
<div class="add-project-header">
<div class="header-left"></div>
<div class="header-right">
<el-button type="default" @click="backClick">返回</el-button>
<template v-if="!loading && !isPreview">
<el-button type="primary" @click="saveClick">保存</el-button>
</template>
</div>
</div>
<div class="tabs-content">
<el-tabs v-model="pageActiveName" type="border-card">
<el-tab-pane label="全生命周期责任书" name="全生命周期责任书">
<div class="project-tab-content">
<el-form :model="formData" :label-width="150" :disabled="isPreview">
<el-collapse v-model="activeCollapse">
<el-collapse-item title="责任书基本信息" name="责任书基本信息">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="层级"></el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="责任书类型"></el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目信息"></el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="责任书文件">
<el-upload
:action="windowConfig.baseUrl + '/api/file/upload'"
:headers="{Authorization: token}"
:show-file-list="false"
multiple
:on-success="addZrsFile"
>
<el-button type="default">上传</el-button>
</el-upload>
<el-button type="default" @click="multiDeleteZrs" :disabled="!zrsSelectIds.length">删除选中文件</el-button>
</el-form-item>
<el-form-item label="">
<el-table :data="zrsData" style="width: 100%" empty-text="暂无数据" border
@selection-change="zrsSelectionChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="originalname" label="文件名" />
<el-table-column prop="updatedAt" label="上传时间" />
<el-table-column prop="size" label="大小" />
<el-table-column fixed="right" label="操作" width="100">
<template #default="{ row, index }">
<!-- 需要在查看表单disabled时保持允许下载 -->
<span class="always-click" @click="downloadFile(row)">下载</span>
<el-button link type="danger" size="small" @click="deleteZrs(index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目名称">
<el-input v-model="formData.projectName" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="年份">
<el-date-picker
v-model="formData.nf"
type="year"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="投资主体">
<el-input v-model="formData.tzzt" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目地点">
<el-input v-model="formData.xmdd" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目开工日期">
<el-date-picker
v-model="formData.xmkgrq"
type="date"
placeholder="请选择"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="项目实施期限">
<el-input-number v-model="formData.xmssqx" :min="0" :max="99999999999.99999999"
controls-position="right"
></el-input-number>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目内容概述">
<el-input v-model="formData.xmnrgs" type="textarea"
:autosize="{minRows: 2, maxRows: 5}"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目经济指标概述">
<el-input v-model="formData.xmjjzbgs" type="textarea"
:autosize="{minRows: 2, maxRows: 5}"
/>
</el-form-item>
</el-col>
</el-row>
</el-collapse-item>
<el-collapse-item title="责任书具体指标" name="责任书具体指标">
</el-collapse-item>
</el-collapse>
</el-form>
</div>
</el-tab-pane>
<el-tab-pane label="全生命周期管理策划" name="全生命周期管理策划">
<div class="project-tab-content"></div>
</el-tab-pane>
<el-tab-pane label="年度经营管理责任书" name="年度经营管理责任书">
<div class="project-tab-content"></div>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, ref, onMounted, getCurrentInstance, computed } from "vue";
import { useRouter, useRoute } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import { useUserStore } from "@/stores/user.js";
const userStore = useUserStore();
const router = useRouter();
const route = useRoute();
const { proxy } = getCurrentInstance();
const pageActiveName = ref("全生命周期责任书");
let token = ref("");
token.value = userStore.authToken || sessionStorage.getItem("authToken") || "";
const activeCollapse = reactive([
"责任书基本信息", "责任书具体指标"
]);
let formData = reactive({});
let loading = ref(false);
let isPreview = !!route.query.isPreview;
// 责任书文件
let zrsData = ref([]);
const addZrsFile = (res, file) => {
zrsData.value.push(res.data);
}
const deleteZrs = (index) => {
ElMessageBox.confirm("确认删除该项?", "提示",{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
zrsData.value.splice(index, 1);
}).catch(() => {})
}
let zrsSelectIds = ref([]);
const zrsSelectionChange = (datas) => {
zrsSelectIds.value = datas.map(item => item.id);
};
const multiDeleteZrs = () => {
ElMessageBox.confirm("确认删除选中数据?", "提示",{
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
zrsData.value = zrsData.value.filter(item => !zrsSelectIds.value.includes(item.id));
}).catch(() => {})
};
const backClick = () => {
router.replace("/targetLiabilityStatement");
}
const saveClick = () => {}
</script>
<style lang="less">
@import "@/styles/manage.less";
.add-project-header{
margin-bottom: 10px;
}
</style>
\ No newline at end of file
<template>
<div class="project-manage-container">
<div class="manage-container">
<div class="project-manage-header">
<div class="header-left"></div>
<div class="header-right">
<el-button type="primary" @click="addStatement">新增</el-button>
</div>
</div>
<div class="project-manage-content" v-loading="loading">
<common-table
:autoHeight="true"
:maxRows="10"
:data="tableData"
:columns="tableColumns"
:total="total"
:current-page="currentPage"
:page-size="pageSize"
:index="true"
:indexLabel="'序号'"
title=""
:border="true"
@size-change="handleSizeChange"
@current-page-change="handleCurrentPageChange"
>
<template #operations="{ row, index }">
<el-button link type="primary" size="small" @click="previewStatement(row)">查看</el-button>
<el-button link type="primary" size="small" @click="editStatement(row)">编辑</el-button>
</template>
</common-table>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, getCurrentInstance } from "vue";
import { useRouter } from "vue-router";
import CommonTable from "@/components/common/commonTable.vue";
const router = useRouter();
const { proxy } = getCurrentInstance();
let tableData = ref([]);
let tableColumns = ref([
{
prop: "projectName",
label: "项目名称",
showOverflowTooltip: true
},
{
prop: "projectCode",
label: "项目编号",
showOverflowTooltip: true
},
{
prop: "operations",
label: "操作",
width: 170,
slot: "operations",
fixed: "right",
align: "center"
}
]);
let loading = ref(false);
let total = ref(0);
let currentPage = ref(1);
let pageSize = ref(10);
// 获取列表数据
const getStatementData = () => {
loading.value = true;
proxy.$post({
url: "/api/project/getTzmbzrsList",
data: {
page: currentPage.value,
pagesize: pageSize.value
},
callback: (data) => {
tableData.value = data.rows;
total.value = data.count;
loading.value = false;
}
})
};
// 分页
const handleSizeChange = (size) => {
pageSize.value = size;
currentPage.value = 1;
getStatementData();
}
const handleCurrentPageChange = (page) => {
currentPage.value = page;
getStatementData();
}
const addStatement = () => {
router.push("/addStatement");
};
const editStatement = (item) => {
router.push({
name: "addStatement",
query: {
projectId: item.id
}
});
};
const previewStatement = (item) => {
router.push({
name: "addStatement",
query: {
isPreview: true,
projectId: item.id
}
})
}
onMounted(() => {
getStatementData();
})
</script>
<style scoped lang="less">
@import "@/styles/manage.less";
</style>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment