whx 1 年之前
父節點
當前提交
1f8f567385
共有 39 個文件被更改,包括 13431 次插入233 次删除
  1. 2 2
      virgo.wzfrontend/console/public/index.html
  2. 1 1
      virgo.wzfrontend/console/src/App.vue
  3. 二進制
      virgo.wzfrontend/console/src/assets/image/common/dataNull.png
  4. 二進制
      virgo.wzfrontend/console/src/assets/image/common/dataUndefined.png
  5. 74 0
      virgo.wzfrontend/console/src/components/common/avatar.vue
  6. 58 0
      virgo.wzfrontend/console/src/components/common/city.vue
  7. 47 0
      virgo.wzfrontend/console/src/components/common/empty.vue
  8. 217 0
      virgo.wzfrontend/console/src/components/common/upload.vue
  9. 59 0
      virgo.wzfrontend/console/src/components/system/main/edit.vue
  10. 64 0
      virgo.wzfrontend/console/src/components/work/space/project/detail.vue
  11. 107 0
      virgo.wzfrontend/console/src/components/work/space/project/edit.vue
  12. 73 0
      virgo.wzfrontend/console/src/components/work/space/set/projectItemForm.vue
  13. 9 73
      virgo.wzfrontend/console/src/httpApi/loginRegister.js
  14. 7 70
      virgo.wzfrontend/console/src/httpApi/system.js
  15. 18 34
      virgo.wzfrontend/console/src/httpApi/work.js
  16. 86 0
      virgo.wzfrontend/console/src/layout/components/breadCrumb.vue
  17. 97 0
      virgo.wzfrontend/console/src/layout/components/changePassword.vue
  18. 35 0
      virgo.wzfrontend/console/src/layout/components/subMenu.vue
  19. 362 0
      virgo.wzfrontend/console/src/layout/components/topNav.vue
  20. 155 0
      virgo.wzfrontend/console/src/layout/components/userDetail.vue
  21. 66 0
      virgo.wzfrontend/console/src/layout/components/userUpdate.vue
  22. 379 0
      virgo.wzfrontend/console/src/layout/loginRegister.vue
  23. 337 7
      virgo.wzfrontend/console/src/layout/work.vue
  24. 9 1
      virgo.wzfrontend/console/src/main.js
  25. 2 1
      virgo.wzfrontend/console/src/router/index.js
  26. 1 8
      virgo.wzfrontend/console/src/router/loginRegister.js
  27. 16 0
      virgo.wzfrontend/console/src/router/modules/space.js
  28. 13 0
      virgo.wzfrontend/console/src/router/modules/system.js
  29. 2 9
      virgo.wzfrontend/console/src/router/work.js
  30. 1 2
      virgo.wzfrontend/console/src/store/getters.js
  31. 2 20
      virgo.wzfrontend/console/src/store/modules/projectBase.js
  32. 10110 0
      virgo.wzfrontend/console/src/uitls/map.js
  33. 4 4
      virgo.wzfrontend/console/src/uitls/permission.js
  34. 221 0
      virgo.wzfrontend/console/src/views/login/index.vue
  35. 41 0
      virgo.wzfrontend/console/src/views/system/index.vue
  36. 154 0
      virgo.wzfrontend/console/src/views/system/main/list.vue
  37. 150 0
      virgo.wzfrontend/console/src/views/work/space/project/list.vue
  38. 451 0
      virgo.wzfrontend/console/src/views/work/space/set/list.vue
  39. 1 1
      virgo.wzfrontend/console/vue.config.js

+ 2 - 2
virgo.wzfrontend/console/public/index.html

@@ -3,9 +3,9 @@
 	<head>
 		<meta charset="utf-8">
 		<meta http-equiv="X-UA-Compatible" content="IE=edge">
-		<link rel="icon" href="https://file-node.oss-cn-shanghai.aliyuncs.com/youji/e34dd8b13d414da3ba3c9695d7404898">
+		<link rel="icon" href="https://file-node.oss-cn-shanghai.aliyuncs.com/youji/3156449b8a1a4874981b2a76d5947721">
 		<link rel="stylesheet" type="text/css" href="<%= BASE_URL %>reset.css" />
-		<link rel="stylesheet" href="//at.alicdn.com/t/c/font_4358860_xs56kkje8vh.css">
+		<link rel="stylesheet" href="//at.alicdn.com/t/c/font_4358860_7ta6ukcxj3a.css">
 		<title>有极</title>
 	</head>
 	<body id="body">

+ 1 - 1
virgo.wzfrontend/console/src/App.vue

@@ -26,5 +26,5 @@
 	};
 </script>
 <style lang="scss">
-
+	@import './assets/scss/index.scss';
 </style>

二進制
virgo.wzfrontend/console/src/assets/image/common/dataNull.png


二進制
virgo.wzfrontend/console/src/assets/image/common/dataUndefined.png


+ 74 - 0
virgo.wzfrontend/console/src/components/common/avatar.vue

@@ -0,0 +1,74 @@
+<template>
+	<div class="hui-avatar">
+		<el-image v-if="user.portrait" :src="user.portrait" fit="cover"></el-image>
+		<div class="el-image" v-else>
+			<div class="avatar-slot">
+				<div :style="`font-size:${size}px;line-height:${lineHeight}px`">
+					{{name}}
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		name: 'avatar',
+		props: {
+			user: {
+				type: Object,
+				default: () => {
+					return {
+						name: ''
+					}
+				}
+			},
+			size: {
+				type: Number,
+				default: 14
+			}
+		},
+		data() {
+			return {
+				lineHeight: 16
+			}
+		},
+		computed: {
+			name() {
+				if (!this.user.name) return '';
+				let name = this.user.name.substring(0, 1);
+				let strCode = name.charCodeAt();
+				if (strCode >= 97 && strCode <= 122) {
+					this.lineHeight = this.size + 2
+				} else {
+					this.lineHeight = this.size;
+				}
+				return name
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+	.hui-avatar {
+		width: 100%;
+		height: 100%;
+
+		.el-image {
+			width: 100%;
+			height: 100%;
+			display: block;
+
+			.avatar-slot {
+				background: $--color-primary;
+				width: 100%;
+				height: 100%;
+				display: flex;
+				flex-direction: column;
+				justify-content: center;
+				align-items: center;
+				color: #fff;
+			}
+		}
+	}
+</style>

+ 58 - 0
virgo.wzfrontend/console/src/components/common/city.vue

@@ -0,0 +1,58 @@
+<template>
+	<div class="city">
+		<el-cascader :props="propsOption" :options="mapDatas" separator="-" v-model="address" :placeholder="'请选择地址'"
+			@change="changeInput" :disabled="disabled"></el-cascader>
+	</div>
+</template>
+
+<script>
+	//区域代码
+	import mapData from '@/uitls/map.js';
+	export default {
+		model: {
+			prop: 'value',
+			event: 'change'
+		},
+		props: {
+			value: [Array],
+			disabled: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				propsOption: {
+					label: 'value'
+				},
+				mapDatas: [],
+				address: []
+			}
+		},
+		created() {
+			this.address = this.value;
+			this.mapDatas = mapData.data;
+		},
+		methods: {
+			changeInput() {
+				this.$emit('change', this.address)
+			}
+		},
+		watch: {
+			value(val) {
+				this.address = val;
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+	.city {
+		display: flex;
+		width: 100%;
+
+		.el-cascader {
+			width: 100%;
+		}
+	}
+</style>

+ 47 - 0
virgo.wzfrontend/console/src/components/common/empty.vue

@@ -0,0 +1,47 @@
+<template>
+	<div class="hui-empty">
+		<img :src="undefinedImage" alt="" :style="'width: '+ width +'px;'" />
+		<div class="space-undefined-text">{{description}}</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		name: 'empty',
+		props: {
+			width: {
+				type: String,
+				default: '160'
+			},
+			description: {
+				type: String,
+				default: '暂无数据'
+			}
+		},
+		data() {
+			return {
+				undefinedImage: require('@/assets/image/common/dataUndefined.png'),
+			}
+		},
+		created() {}
+	}
+</script>
+
+<style lang="scss">
+	.hui-empty {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		flex-direction: column;
+
+		img {
+			width: 160px;
+		}
+
+		.space-undefined-text {
+			margin-top: 10px;
+			opacity: 0.6;
+			line-height: 20px;
+		}
+	}
+</style>

+ 217 - 0
virgo.wzfrontend/console/src/components/common/upload.vue

@@ -0,0 +1,217 @@
+<template>
+	<div class="common-update">
+		<div v-if="type === 'preview'">
+			<div class="no-tips" v-if="fileList.length === 0">暂无附件</div>
+			<div class="common-perview-image" v-else>
+				<div class="common-update-image-box" v-for="(item,index) in fileList" :key="item.id">
+					<el-image :src="item.url" :preview-src-list="[item.url]">
+						<div slot="error" class="image-slot">
+							<el-tooltip class="item" effect="dark" :content="item.name" placement="bottom">
+								<div class="image-text">{{item.type.toUpperCase()}}</div>
+							</el-tooltip>
+						</div>
+					</el-image>
+				</div>
+			</div>
+		</div>
+		<div class="common-update-image" v-else>
+			<div class="common-update-image-box" v-for="(item,index) in fileList" :key="item.id">
+				<el-image :src="item.url" :preview-src-list="[item.url]">
+					<div slot="error" class="image-slot">
+						<el-tooltip class="item" effect="dark" :content="item.name" placement="bottom">
+							<div class="image-text">{{item.type.toUpperCase()}}</div>
+						</el-tooltip>
+					</div>
+				</el-image>
+				<div class="common-update-close" @click="removeFile(index)">
+					<i class="el-icon-close"></i>
+				</div>
+			</div>
+			<el-upload :action="action" :headers="headers" :show-file-list="false" name="uploadFile"
+				:before-upload="beforeUpload" :on-success="successFile" :on-error="errorFile"
+				v-if="fileList.length < maxLen">
+				<div class="common-update-button">
+					<i class="iconfont huifont-xinzeng"></i>
+					<div class="common-update-button-label">{{text}}</div>
+				</div>
+			</el-upload>
+		</div>
+	</div>
+</template>
+
+<script>
+	import config from '@/config';
+	import {
+		getToken
+	} from '@/uitls/auth';
+	export default {
+		props: {
+			list: {
+				type: Array,
+				default: () => {
+					return []
+				}
+			},
+			type: {
+				type: String,
+				default: 'preview'
+			},
+			maxLen: {
+				type: Number,
+				default: 5
+			},
+			text: {
+				type: String,
+				default: '上传附件'
+			}
+		},
+		data() {
+			return {
+				action: config.baseURL + '/file/filenode/-1', //上传地址
+				headers: {
+					token: ''
+				},
+				url: '',
+				srcList: [],
+				fileList: []
+			};
+		},
+		created() {
+			this.headers.token = getToken();
+			this.fileList = JSON.parse(JSON.stringify(this.list));
+		},
+		methods: {
+			beforeUpload(file) {
+				//上传前
+				if (parseInt(file.size) / 1024 / 1024 > 30) {
+					//判断上传的文件不大于30M
+					this.$message.warning('请上传小于30M的文件');
+					return false;
+				}
+			},
+			successFile(response, file, fileList) {
+				//上传成功
+				if (!response.data) return this.errorFile();
+				this.$message.success('上传成功');
+				let data = response.data;
+				let typeList = data.name.split('.');
+				console.log(this.fileList);
+				this.fileList.push({
+					id: data.id,
+					name: data.name,
+					url: data.node.url,
+					type: typeList[typeList.length - 1]
+				});
+			},
+			errorFile() {
+				//上传失败
+				this.$message.error('上传失败');
+			},
+			removeFile(index) {
+				this.$confirm('确定要删除该文件?', () => {
+					this.fileList.splice(index, 1);
+				});
+			}
+		},
+		watch: {
+			list(val) {
+				this.fileList = JSON.parse(JSON.stringify(val))
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+	.common-update {
+		display: flex;
+		flex-wrap: wrap;
+
+		.common-update-button {
+			width: 100px;
+			height: 100px;
+			border: 1px dashed $--input-border;
+			display: flex;
+			color: $--color-common;
+			flex-direction: column;
+			justify-content: center;
+			margin: 4px 0;
+
+			.huifont-xinzeng {
+				line-height: 20px;
+				font-size: 20px;
+			}
+
+			.common-update-button-label {
+				font-size: 14px;
+				line-height: 20px;
+				padding-top: 10px;
+			}
+		}
+
+		.common-perview-image {
+			display: flex;
+			flex-wrap: wrap;
+
+			.el-image {
+				width: 64px;
+				height: 64px;
+				border-radius: 2px;
+				background: transparent;
+			}
+		}
+
+		.image-slot {
+			width: 100%;
+			height: 100%;
+			border: 1px solid $--input-border;
+
+			.image-text {
+				font-size: 20px;
+				width: 100%;
+				height: 100%;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				color: $--color-common;
+				font-weight: bold;
+			}
+		}
+
+		.common-update-image-box {
+			display: flex;
+			position: relative;
+			margin-right: 4px;
+		}
+
+		.common-update-image {
+			display: flex;
+			flex-wrap: wrap;
+
+			.common-update-image-box {
+				margin: 4px 8px 4px 0;
+			}
+
+			.el-image {
+				width: 100px;
+				height: 100px;
+				border-radius: 2px;
+				background: transparent;
+			}
+
+			.common-update-close {
+				position: absolute;
+				right: -7px;
+				top: -7px;
+				background: #394358;
+				color: $--color-common;
+				width: 14px;
+				height: 14px;
+				line-height: 14px;
+				text-align: center;
+				border-radius: 50%;
+				font-size: 10px;
+				cursor: pointer;
+			}
+		}
+	}
+</style>

+ 59 - 0
virgo.wzfrontend/console/src/components/system/main/edit.vue

@@ -0,0 +1,59 @@
+<template>
+	<div class="hui-flex hui-dialog">
+		<div class="hui-flex-box hui-dialog-content">
+			<el-form ref="menuForm" :model="menuForm" label-position="top">
+				<el-form-item label="菜单名称">
+					<el-input v-model="menuForm.title"></el-input>
+				</el-form-item>
+				<el-form-item label="菜单URL">
+					<el-input v-model="menuForm.index"></el-input>
+				</el-form-item>
+				<el-form-item label="菜单图标">
+					<el-input v-model="menuForm.iconClass"></el-input>
+				</el-form-item>
+				<el-form-item label="是否菜单">
+					<el-radio v-model="menuForm.isMenu" label="1">是</el-radio>
+					<el-radio v-model="menuForm.isMenu" label="2">否</el-radio>
+				</el-form-item>
+			</el-form>
+		</div>
+		<div class="hui-dialog-submit">
+			<el-button size="medium" @click="$emit('callback')">取 消</el-button>
+			<el-button size="medium" type="primary" @click="submit">保 存</el-button>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		props: ['updateData'],
+		data() {
+			return {
+				menuForm: {
+					title: '',
+					index: '',
+					iconClass: '',
+					isMenu: '1'
+				}
+			}
+		},
+		created() {
+			let _self = this;
+			if (_self.updateData.id) _self.menuForm = _self.updateData;
+		},
+		methods: {
+			sureIncrease() { //返回新增数据
+				let _self = this;
+				if (_self.menuForm.index == '') delete _self.menuForm.index;
+				return _self.menuForm;
+			},
+			submit() {
+				this.$emit('sure')
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+
+</style>

+ 64 - 0
virgo.wzfrontend/console/src/components/work/space/project/detail.vue

@@ -0,0 +1,64 @@
+<template>
+	<div class="hui-detail">
+		<div class="hui-detail-title">基础信息</div>
+		<div class="hui-detail-content">
+			<div class="hui-detail-item">
+				<div class="hui-detail-label">项目名称</div>
+				<div class="hui-detail-value">{{detail.name}}</div>
+			</div>
+			<div class="hui-detail-item">
+				<div class="hui-detail-label">项目区域</div>
+				<div class="hui-detail-value">{{detail.address.join('-')}}</div>
+			</div>
+			<div class="hui-detail-item">
+				<div class="hui-detail-label">具体地点</div>
+				<div class="hui-detail-value">{{detail.specific}}</div>
+			</div>
+			<div class="hui-detail-item">
+				<div class="hui-detail-label">项目描述</div>
+				<div class="hui-detail-value">{{detail.comment}}</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+	import {
+		getProjectDetailById
+	} from '@/httpApi/work'
+	export default {
+		props: ['detailId'],
+		data() {
+			return {
+				detail: {
+					name: '', //项目名称
+					address: [],
+					comment: '',
+					data: '',
+					organizationId: '',
+					picture: '',
+					tagId: ''
+				}
+			}
+		},
+		created() {
+			if (this.detailId) this.init();
+		},
+		methods: {
+			init() {
+				getProjectDetailById(this.detailId).then(res => {
+					if (res.state) {
+						let obj = res.data;
+						let data = {};
+						if (obj.data) data = JSON.parse(obj.data);
+						obj.address = JSON.parse(obj.address);
+						this.detail = Object.assign(obj, data);
+					}
+				})
+			}
+		},
+	}
+</script>
+<style lang="scss">
+
+</style>

+ 107 - 0
virgo.wzfrontend/console/src/components/work/space/project/edit.vue

@@ -0,0 +1,107 @@
+<template>
+	<div class="hui-flex hui-dialog">
+		<div class="hui-flex-box hui-dialog-content">
+			<el-form ref="projectForm" label-position="top" :model="projectForm">
+				<el-form-item label="项目名称" prop="name" :rules="[{required: true, message: '请输入项目名称'}]">
+					<el-input type="text" v-model="projectForm.name" placeholder="请输入项目名称"></el-input>
+				</el-form-item>
+				<el-form-item label="项目区域" prop="address" :rules="[{required: true, message: '请选择项目区域'}]">
+					<city v-model="projectForm.address"></city>
+				</el-form-item>
+				<el-form-item label="具体地点">
+					<el-input type="text" v-model="specific" placeholder="请输入具体地点">
+					</el-input>
+				</el-form-item>
+				<el-form-item label="项目描述" class="hui-textarea">
+					<el-input type="textarea" v-model="projectForm.comment" placeholder="请输入项目描述" resize="none">
+					</el-input>
+				</el-form-item>
+				<el-form-item label="项目配图" class="hui-textarea">
+					<upload ref="upload" :list="responsibility" type="insert"></upload>
+				</el-form-item>
+			</el-form>
+		</div>
+		<div class="hui-dialog-submit">
+			<el-button size="medium" @click="$emit('callback')">取 消</el-button>
+			<el-button size="medium" type="primary" @click="submit">保 存</el-button>
+		</div>
+	</div>
+</template>
+
+<script>
+	import {
+		insertProject,
+		getProjectDetailById,
+		updateProject
+	} from '@/httpApi/work'
+	import upload from '@/components/common/upload'
+	import city from '@/components/common/city'
+	export default {
+		props: ['isUpdate', 'detailId'],
+		data() {
+			return {
+				projectForm: {
+					name: '', //项目名称
+					address: [],
+					comment: '',
+					data: '',
+					organizationId: '',
+					picture: '',
+					tagId: ''
+				},
+				specific: '',
+				responsibility: []
+			}
+		},
+		created() {
+			this.projectForm['organizationId'] = this.$store.getters.user.organization.id;
+			if (this.isUpdate) {
+				console.log(this.detailId);
+				getProjectDetailById(this.detailId).then(res => {
+					if (res.state) {
+						this.projectForm = res.data;
+						this.projectForm.address = JSON.parse(this.projectForm.address);
+						if (this.projectForm.picture) this.responsibility = JSON.parse(this.projectForm.picture);
+						if (this.projectForm.data) {
+							let data = JSON.parse(this.projectForm.data);
+							this.specific = data.specific;
+						}
+					}
+				})
+			}
+		},
+		methods: {
+			submit() {
+				this.$refs.projectForm.validate((valid) => {
+					if (valid) {
+						let postData = JSON.parse(JSON.stringify(this.projectForm));
+						postData.data = JSON.stringify({
+							specific: this.specific
+						});
+						postData['picture'] = JSON.stringify(this.$refs.upload.fileList);
+						postData['address'] = JSON.stringify(this.projectForm.address);
+						if (this.isUpdate) {
+							updateProject(postData).then(this.successFunc);
+						} else {
+							insertProject(postData).then(this.successFunc);
+						}
+					} else {
+						return false;
+					}
+				});
+			},
+			successFunc(res) {
+				if (res.state) {
+					this.$message.success('操作成功');
+					this.$emit('callback', 'init');
+				}
+			}
+		},
+		components: {
+			city,
+			upload
+		},
+	}
+</script>
+
+<style lang="scss"></style>

+ 73 - 0
virgo.wzfrontend/console/src/components/work/space/set/projectItemForm.vue

@@ -0,0 +1,73 @@
+<template>
+	<div class="hui-flex hui-dialog">
+		<div class="hui-flex-box hui-dialog-content">
+			<el-form ref="projectItemForm" :model="projectItemForm" label-position="top">
+				<el-form-item label="单位名称">
+					<el-input type="text" v-model="projectItemForm.name" placeholder="请输入单位名称"></el-input>
+				</el-form-item>
+				<el-form-item label="单位编号">
+					<el-input type="text" v-model="projectItemForm.number" placeholder="请输入单位编号" :disabled="isUpdate">
+					</el-input>
+				</el-form-item>
+				<el-form-item label="单位编码">
+					<el-input type="text" v-model="projectItemForm.code" placeholder="请输入单位编码"></el-input>
+				</el-form-item>
+			</el-form>
+		</div>
+		<div class="hui-dialog-submit">
+			<el-button size="medium" @click="$emit('callback')">取 消</el-button>
+			<el-button size="medium" type="primary" @click="submit">保 存</el-button>
+		</div>
+	</div>
+</template>
+
+<script>
+	import {
+		insertProjectItem,
+		getProjectItemDetailById,
+		updateProjectItem
+	} from '@/httpApi/work'
+	export default {
+		props: ['isUpdate', 'detailId'],
+		data() {
+			return {
+				projectItemForm: {
+					name: '',
+					number: '',
+					type: '',
+					bim: 1,
+					code: ''
+				},
+				projectItemRuler: {},
+			}
+		},
+		created() {
+			if (this.isUpdate) {
+				getProjectItemDetailById(this.detailId).then(res => {
+					if (res.state) {
+						let data = res.data;
+						this.projectItemForm = data;
+					}
+				})
+			}
+		},
+		methods: {
+			submit() {
+				if (this.isUpdate) {
+					delete this.projectItemForm.number;
+					updateProjectItem(this.projectItemForm).then(this.successFunc)
+				} else {
+					insertProjectItem(this.$store.getters.project.id, this.projectItemForm).then(this.successFunc)
+				}
+			},
+			successFunc(res) {
+				if (res.state) {
+					this.$message.success('操作成功');
+					this.$emit('callback', 'init');
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss"></style>

+ 9 - 73
virgo.wzfrontend/console/src/httpApi/loginRegister.js

@@ -1,42 +1,22 @@
 import request from '@/axios'
 
-/* 
- * 验证手机号是否已注册运营
- * 
- */
-export function checkPhone(phone) {
-	return request({
-		url: `/manager/register/operate/vPhone/${phone}`,
-		method: 'get'
-	})
-}
-/* 
- * 验证手机号是否已注册运营
- * 
- */
-export function testPhone(phone) {
-	return request({
-		url: `/manager/register/vPhone/${phone}`,
-		method: 'get'
-	})
-}
 /* 
  * 获取图片验证码
  * 
  */
 export function getImgCode() {
 	return request({
-		url: `/manager/register/pCode`,
+		url: `/manager/pCode`,
 		method: 'get'
 	})
 }
 /* 
- * 获取手机验证码
+ * 发送手机验证码
  * 
  */
-export function verifyPhoneCode(phone, vCode) {
+export function sendPhoneCode(phone, vCode) {
 	return request({
-		url: `/manager/register/vCode/${phone}/${vCode}`,
+		url: `/manager/send/${phone}/${vCode}`,
 		method: 'get'
 	})
 }
@@ -51,17 +31,6 @@ export function login(data) {
 		data: data
 	})
 }
-/* 
- * 注册
- * 
- */
-export function register(data) {
-	return request({
-		url: `/manager/register`,
-		method: 'post',
-		data: data
-	})
-}
 
 /* 
  * 获取当前登录者信息
@@ -70,7 +39,7 @@ export function register(data) {
  */
 export function getUserInfo(data) {
 	return request({
-		url: `/manager/operateUserContext`,
+		url: `/manager/userContext`,
 		method: 'get'
 	})
 }
@@ -81,7 +50,7 @@ export function getUserInfo(data) {
  */
 export function selectOrangaized(data) {
 	return request({
-		url: `/manager/operateUserContext/operateOrganization`,
+		url: `/manager/userContext/organization`,
 		method: 'post',
 		data: data
 	})
@@ -92,7 +61,7 @@ export function selectOrangaized(data) {
  */
 export function selectProject(projectId) {
 	return request({
-		url: `/manager/operateUserContext/project/${projectId}`,
+		url: `/manager/userContext/project/${projectId}`,
 		method: 'put',
 	})
 }
@@ -101,9 +70,9 @@ export function selectProject(projectId) {
  * @param null 
  * 
  */
-export function getOrganizedProjectList(params) {
+export function getOrganizedProjectList(organizationId) {
 	return request({
-		url: `/api/project/operate/${params}`,
+		url: `/api/project/getOrganization/${organizationId}/`,
 		method: 'get',
 	})
 }
@@ -118,37 +87,4 @@ export function updateUserDetails(data) {
 		method: 'post',
 		data: data
 	})
-}
-/* 
- * 获取项目组织下个人信息
- * 
- */
-export function getOperationUserInfo(data) {
-	return request({
-		url: `/manager/info/get`,
-		method: 'post',
-		data: data
-	})
-}
-/* 
- * 新增项目组织下个人信息
- * 
- */
-export function insertOperationUserInfo(data) {
-	return request({
-		url: `/manager/info`,
-		method: 'post',
-		data: data
-	})
-}
-/* 
- * 修改项目组织下个人信息
- * 
- */
-export function updateOperationUserInfo(data) {
-	return request({
-		url: `/manager/info`,
-		method: 'put',
-		data: data
-	})
 }

+ 7 - 70
virgo.wzfrontend/console/src/httpApi/system.js

@@ -1,97 +1,34 @@
 import request from '@/axios'
-import config from '@/config'
 
 /* 
  * 获取菜单列表
  * 
  */
 export function getMenuList() {
-	return request.get('/manager/operateResource/list');
-}
-/* 
- * 编辑菜单
- * 
- */
-export function updateMenu(data) {
-	return request.post('/manager/operateResource/update', data);
-}
-/* 
- * 获取待转换列表
- * 
- */
-export function getAdjustedList() {
-	return request.get('/file/category/adjusted');
-}
-/* 
- * 新增文档模板
- * 
- * 
- */
-export function insertDocumentTemplate(data) {
-	return request.post(`/file/category/${data.parentId}/template`, data);
-}
-/* 
- * 下载文件
- * 
- * 
- */
-export function downloadFile(fileId) {
-	return window.location.href = config.baseURL + '/file/filenode/' + fileId;
-}
-/* 
- * 获取设备层级
- * 
- * 
- */
-export function getDeviceModel() {
-	return request({
-		url: `/operate/operateDeviceLevelModel`,
-		method: 'get'
-	})
-}
-/* 
- * 获取通过id设备层级
- * 
- * 
- */
-export function getDeviceModelById(id) {
 	return request({
-		url: `/operate/operateDeviceLevelModel/get/${id}`,
+		url: `/manager/resource/list`,
 		method: 'get'
 	})
 }
 /* 
- * 新增设备层级
- * 
+ * 新增菜单
  * 
  */
-export function insertDeviceModel(data) {
+export function insertMenu(data) {
 	return request({
-		url: `/operate/operateDeviceLevelModel`,
+		url: `/manager/resource`,
 		method: 'post',
 		data: data
 	})
 }
 /* 
- * 编辑设备层级
- * 
+ * 编辑菜单
  * 
  */
-export function updateDeviceModel(data) {
+export function updateMenu(data) {
 	return request({
-		url: `/operate/operateDeviceLevelModel`,
+		url: `/manager/resource/update`,
 		method: 'put',
 		data: data
 	})
-}
-/* 
- * 删除设备层级
- * 
- * 
- */
-export function deleteDeviceModel(id) {
-	return request({
-		url: `/operate/operateDeviceLevelModel/${id}`,
-		method: 'delete'
-	})
 }

+ 18 - 34
virgo.wzfrontend/console/src/httpApi/work.js

@@ -6,31 +6,32 @@ import request from '@/axios'
  */
 export function getProjectListByPage(data) {
 	return request({
-		url: `/api/project/list`,
+		url: `/api/project/${data.currPage}/${data.pageSize}`,
 		method: 'post',
 		data: data
 	})
 }
 /* 
- * 获取项目类型列表
+ * 新增项目
  * 
  * 
  */
-export function getProjectTypeList() {
+export function insertProject(data) {
 	return request({
-		url: `/api/part/list`,
-		method: 'get'
+		url: `/api/project`,
+		method: 'post',
+		data: data
 	})
 }
 /* 
- * 新增项目
+ * 编辑项目
  * 
  * 
  */
-export function insertProject(operateOrganizationId, data) {
+export function updateProject(data) {
 	return request({
-		url: `/api/project/operate/${operateOrganizationId}`,
-		method: 'post',
+		url: `/api/project/update`,
+		method: 'put',
 		data: data
 	})
 }
@@ -39,9 +40,9 @@ export function insertProject(operateOrganizationId, data) {
  * 
  * 
  */
-export function getProjectDetailById(operateOrganizationId, id) {
+export function getProjectDetailById(id) {
 	return request({
-		url: `/api/project/${operateOrganizationId}/${id}`,
+		url: `/api/project/getProject/${id}`,
 		method: 'get'
 	})
 }
@@ -56,18 +57,12 @@ export function deleteProjectById(id) {
 		method: 'delete'
 	})
 }
-/* 
- * 编辑项目
- * 
- * 
- */
-export function updateProject(data) {
-	return request({
-		url: `/api/project/update`,
-		method: 'put',
-		data: data
-	})
-}
+
+
+
+
+
+
 /* 
  * 获取项目单位工程列表
  * 
@@ -147,17 +142,6 @@ export function deleteProjectItemById(id) {
 		method: 'delete'
 	})
 }
-/* 
- * 通过组织id获取项目列表
- * 
- * 
- */
-export function getProjectListByOrganizationId(id) {
-	return request({
-		url: `/api/project/operate/${id}`,
-		method: 'get'
-	})
-}
 /* 
  * 获取组织项目部门列表
  * 

+ 86 - 0
virgo.wzfrontend/console/src/layout/components/breadCrumb.vue

@@ -0,0 +1,86 @@
+<template>
+	<div class="bread-crumb">
+		<div class="crumb-box">
+			<div class="crumb-item" v-for="(item,index) in levelList" :key="index">
+				<span>{{item}}</span>
+				<span class="tips" v-if="index !== levelList.length - 1">/</span>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		name: 'breadCrumb',
+		data() {
+			return {
+				levelList: []
+			}
+		},
+		watch: {
+			$route() {
+				this.getBreadcrumb();
+			}
+		},
+		created() {
+			this.menuList = this.$store.getters.menuData;
+			this.getBreadcrumb();
+		},
+		methods: {
+			getBreadcrumb() {
+				this.levelList = this.findParent(this.menuList, this.$route.path);
+				if (this.levelList.length === 0) this.levelList.push(this.$route.name);
+			},
+			findParent(dataSource, path) {
+				const parentIds = []; // 用于存储所有父节点ID的数组
+				// 定义一个递归函数,用于遍历整棵树并查找子节点的所有父节点
+				function traverse(node, path) {
+					if (node.index === path) { // 如果当前节点的ID等于子节点的ID,则表示已经找到了子节点,可以开始向上查找父节点
+						parentIds.push(node.title);
+						return true; // 返回true表示已经找到了子节点
+					}
+					if (node.children) { // 如果当前节点有子节点,则继续遍历子节点
+						for (const childNode of node.children) {
+							if (traverse(childNode, path)) { // 如果在子节点中找到了子节点的父节点,则将当前节点的ID添加到父节点ID数组中,并返回true表示已经找到了子节点
+								parentIds.unshift(node.title);
+								return true;
+							}
+						}
+					}
+					return false; // 如果当前节点不是子节点的父节点,则返回false
+				}
+				// 从根节点开始遍历整棵树,并调用递归函数查找子节点的所有父节点
+				for (const node of dataSource) {
+					if (traverse(node, path)) { // 如果在当前节点的子树中找到了子节点的父节点,则直接退出循环
+						break;
+					}
+				}
+				return parentIds; // 返回所有父节点ID的数组
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.bread-crumb {
+		.crumb-box {
+			position: relative;
+			padding-top: 1px;
+			display: flex;
+			align-items: center;
+
+			.crumb-item {
+				opacity: 0.5;
+				font-weight: 400;
+			}
+
+			.crumb-item:last-child {
+				opacity: 1;
+			}
+
+			.tips {
+				margin: 0px 3px;
+			}
+		}
+	}
+</style>

+ 97 - 0
virgo.wzfrontend/console/src/layout/components/changePassword.vue

@@ -0,0 +1,97 @@
+<template>
+	<div class="hui-flex hui-dialog">
+		<div class="hui-flex-box hui-dialog-content">
+			<el-form :model="form" :rules="changePasswordRulers" ref="form" label-position="top">
+				<el-form-item label="密码" prop="pass" class="hui-textarea">
+					<el-input type="password" v-model="form.pass" autocomplete="off"></el-input>
+				</el-form-item>
+				<el-form-item label="确认密码" prop="checkPass" class="hui-textarea">
+					<el-input type="password" v-model="form.checkPass" autocomplete="off"></el-input>
+				</el-form-item>
+			</el-form>
+		</div>
+		<div class="hui-dialog-submit">
+			<el-button size="medium" @click="$emit('callback')">取 消</el-button>
+			<el-button size="medium" type="primary" @click="submit">保 存</el-button>
+		</div>
+	</div>
+</template>
+
+<script>
+	import {
+		updateUserDetails
+	} from '@/httpApi/loginRegister'
+	import {
+		removeToken
+	} from '@/uitls/auth';
+	export default {
+		data() {
+			return {
+				form: { //修改密码表单
+					oldPass: '',
+					pass: '',
+					checkPass: ''
+				},
+				changePasswordRulers: {
+					oldPass: [{
+						required: true,
+						message: '请输入原密码',
+						trigger: 'blur'
+					}],
+					pass: [{
+						required: true,
+						message: '请输入密码',
+						trigger: 'blur'
+					}, {
+						min: 6,
+						max: 18,
+						message: '密码长度在6-18位之间',
+					}]
+				}, //表单验证
+				checkPassFn: (rule, value, callback) => { //再次输入密码验证规则
+					if (value !== this.form.pass) {
+						callback(new Error('两次输入密码不一致!'));
+					} else {
+						callback();
+					}
+				}
+			}
+		},
+		created() {
+			this.changePasswordRulers['checkPass'] = [{
+				required: true,
+				message: '请输入确认密码',
+				trigger: 'blur'
+			}, {
+				validator: this.checkPassFn,
+				trigger: 'blur'
+			}, {
+				validator: this.checkPassFn,
+				trigger: 'change'
+			}]
+		},
+		methods: {
+			submit(fn) {
+				this.$refs.form.validate((valid) => {
+					if (valid) {
+						let data = {
+							id: this.$store.getters.user.userId,
+							pwd: this.form.pass
+						}
+						updateUserDetails(data).then(res => {
+							if (res.state) {
+								this.$message.success('修改成功,请重新登录');
+								removeToken();
+								window.location.replace(window.location.origin);
+							}
+						})
+					} else {
+						return false;
+					}
+				});
+			},
+		}
+	}
+</script>
+
+<style lang="scss"></style>

+ 35 - 0
virgo.wzfrontend/console/src/layout/components/subMenu.vue

@@ -0,0 +1,35 @@
+<template>
+	<div>
+		<template v-for="(item,index) in menuData">
+			<div v-if="item.isMenu === '1'" :class="'menu-index-'+menuIndex">
+				<el-submenu :index="item.title"
+					v-if="item.children && item.children.length > 0 && item.children.filter(node=>node.isMenu==='1').length > 0"
+					:key="index">
+					<template slot="title">
+						<i v-if="item.iconClass" :class="item.iconClass + ' icon iconfont'"></i>
+						<span slot="title" class="menu-title">{{item.title}}</span>
+					</template>
+					<sub-menu :menuData="item.children" :menuIndex="menuIndex+1"></sub-menu>
+				</el-submenu>
+				<el-menu-item :index="item.index" v-else :key="index">
+					<i v-if="item.iconClass" :class="item.iconClass + ' icon'"></i>
+					<span slot="title" class="menu-title">{{item.title}}</span>
+				</el-menu-item>
+			</div>
+		</template>
+	</div>
+</template>
+
+<script>
+	import subMenu from '@/layout/components/subMenu'
+	export default {
+		name: 'sub-menu',
+		props: ['menuData', 'menuIndex'],
+		components: {
+			subMenu
+		}
+	}
+</script>
+
+<style>
+</style>

+ 362 - 0
virgo.wzfrontend/console/src/layout/components/topNav.vue

@@ -0,0 +1,362 @@
+<template>
+	<div class="work-layout-title">
+		<div class="work-layout-left">
+			<div class="work-layout-image">
+				<img src="https://file-node.oss-cn-shanghai.aliyuncs.com/youji/e34dd8b13d414da3ba3c9695d7404898"
+					alt="" />
+			</div>
+			<div class="work-layout-label">智慧运营平台</div>
+			<div class="work-layout-button" @click="$router.push('/')">
+				<i class="iconfont huifont-shouye"></i><span>首页</span>
+			</div>
+			<div class="work-layout-line"></div>
+			<el-dropdown trigger="click" @visible-change="projectVisible" @command="projectCommand"
+				v-if="projects.name">
+				<div class="work-layout-project">
+					<span>{{projects.name}}</span>
+					<i :class="'iconfont huifont-xiala-top'+ (projectDropdown ? ' dropdown-icon' : '')"></i>
+				</div>
+				<el-dropdown-menu class="project-dropdown" slot="dropdown">
+					<el-dropdown-item :command="item.id" v-for="(item,index) in projectList" :key="item.id">
+						{{item.name}}
+					</el-dropdown-item>
+				</el-dropdown-menu>
+			</el-dropdown>
+		</div>
+		<div class="work-layout-right">
+			<el-dropdown @visible-change="value => userDropdown = value" @command="userCommand">
+				<div class="work-layout-user">
+					<div class="work-layout-avatar">
+						<avatar :user="users"></avatar>
+					</div>
+					<i :class="'iconfont huifont-gerenzhongxinxiala'+ (userDropdown ? ' dropdown-icon' : '')"></i>
+				</div>
+				<el-dropdown-menu class="user-dropdown" slot="dropdown">
+					<el-dropdown-item command="user">{{users.name}}</el-dropdown-item>
+					<el-dropdown-item command="detail">个人信息</el-dropdown-item>
+					<el-dropdown-item command="password">修改密码</el-dropdown-item>
+					<el-dropdown-item command="loginout">退出登录</el-dropdown-item>
+				</el-dropdown-menu>
+			</el-dropdown>
+		</div>
+		<el-dialog title="修改密码" :visible.sync="visible" width="900px" :append-to-body="true">
+			<change-password v-if="visible" @callback="visible=false"></change-password>
+		</el-dialog>
+		<el-drawer title="个人信息" class="user-drawer" :modal="false" :visible.sync="drawer" :size="400"
+			:append-to-body="true">
+			<user-detail v-if="drawer"></user-detail>
+		</el-drawer>
+	</div>
+</template>
+
+<script>
+	import changePassword from './changePassword'
+	import userDetail from './userDetail'
+	import {
+		removeToken,
+		setComment
+	} from '@/uitls/auth';
+	import {
+		selectProject,
+		getOrganizedProjectList
+	} from '@/httpApi/loginRegister'
+	import {
+		mapGetters
+	} from 'vuex';
+	import avatar from '@/components/common/avatar'
+	export default {
+		data() {
+			return {
+				projects: {},
+				users: {},
+				userDropdown: false,
+				projectDropdown: false,
+				projectList: [],
+				visible: false,
+				drawer: false
+			}
+		},
+		created() {
+			this.init();
+			this.initProject();
+		},
+		methods: {
+			init() {
+				this.projects = this.$store.getters.project;
+				this.users = this.$store.getters.user;
+				this.users['name'] = this.users.userName;
+			},
+			loginout() {
+				this.$confirm('是否要退出登录?', () => {
+					removeToken();
+					window.location.replace(window.location.origin);
+					this.$message.success('退出成功');
+				});
+			},
+			initProject() {
+				getOrganizedProjectList(this.$store.getters.organization.id).then(res => {
+					if (res.state) {
+						this.projectList = res.data || [];
+						if (this.project.id) return;
+						if (this.projectList.length === 1) this.changeProject(this.projectList[0]);
+					}
+				})
+			},
+			projectVisible(value) {
+				if (value) this.initProject();
+				this.projectDropdown = value;
+			},
+			projectCommand(command) {
+				let data = this.projectList.filter(node => node.id === command)[0];
+				this.changeProject(data);
+			},
+			changeProject(data) {
+				if (!data) return;
+				data.projectItemList = data.projectItemList || [];
+				data.projectItemList.sort((a, b) => {
+					return a.id - b.id;
+				});
+				selectProject(data.id).then(res => {
+					if (res.state) {
+						let user = res.data;
+						this.$store.dispatch('projectBase/changeProject', data);
+						localStorage.setItem('projectId', data.id);
+						this.$store.dispatch('app/changeUser', user);
+						this.$store.dispatch('app/changeMenuData', user.resource ? JSON.parse(user.resource) : []);
+						setComment(user.menu ? user.menu : JSON.stringify([]));
+						this.init();
+						this.$router.push({
+							path: '/',
+							replace: true
+						})
+						this.$message.success('切换成功');
+					} else {
+						this.$message.error('切换失败');
+					}
+				});
+			},
+			userCommand(command) {
+				switch (command) {
+					case 'detail':
+						this.drawer = true;
+						break;
+					case 'password':
+						this.visible = true;
+						break;
+					case 'loginout':
+						this.loginout();
+						break;
+					default:
+						break;
+				}
+			}
+		},
+		components: {
+			changePassword,
+			userDetail
+		},
+		watch: {
+			user() {
+				this.init();
+			},
+			project() {
+				this.init();
+				this.initProject('reload');
+			}
+		},
+		computed: {
+			...mapGetters(['user', 'project'])
+		},
+	}
+</script>
+
+<style lang="scss">
+	.work-layout-title {
+		display: flex;
+		height: 52px;
+		position: absolute;
+		left: 0;
+		right: 0;
+		top: 0;
+		justify-content: space-between;
+		background: #1E2430;
+
+		.work-layout-right {
+			height: 100%;
+			padding-right: 24px;
+			display: flex;
+			align-items: center;
+
+			.work-layout-type {
+				display: flex;
+				align-items: center;
+				cursor: pointer;
+				height: 100%;
+				padding: 0 15px;
+
+				.iconfont {
+					font-size: 22px;
+				}
+
+				span {
+					font-size: 13px;
+					margin-left: 2px;
+				}
+			}
+
+			.work-layout-type:hover,
+			.work-layout-type.active {
+				background: $--color-primary;
+				color: #fff;
+			}
+
+			.work-layout-badge {
+				margin-right: 32px;
+				cursor: pointer;
+				margin-left: 45px;
+
+				.iconfont {
+					font-size: 22px;
+				}
+
+				.el-badge__content {
+					border: none;
+				}
+			}
+
+			.work-layout-user {
+				display: flex;
+				align-items: center;
+				cursor: pointer;
+
+				.work-layout-avatar {
+					width: 32px;
+					height: 32px;
+					border-radius: 50%;
+					overflow: hidden;
+					margin-right: 8px;
+				}
+
+				.iconfont {
+					font-size: 14px;
+					color: $--color-common;
+					transition: all 300ms;
+				}
+
+				.dropdown-icon {
+					transform: rotate(180deg);
+				}
+			}
+		}
+
+		.work-layout-left {
+			height: 100%;
+			padding-left: 24px;
+			display: flex;
+			align-items: center;
+
+			.work-layout-image {
+				width: 36px;
+				height: 36px;
+				border-radius: 4px;
+				overflow: hidden;
+
+				img {
+					width: 100%;
+					height: 100%;
+				}
+			}
+
+			.work-layout-label {
+				padding-left: 10px;
+				font-size: 18px;
+				font-weight: bold;
+				color: #fff;
+				font-weight: 600;
+				margin-right: 77px;
+			}
+
+			.work-layout-button {
+				background-color: #2b2f3a;
+				width: 82px;
+				height: 36px;
+				border-radius: 4px;
+				display: flex;
+				align-items: center;
+				cursor: pointer;
+				justify-content: center;
+
+				.iconfont {
+					font-size: 23px;
+				}
+
+				span {
+					font-size: 13px;
+					margin-left: 6px;
+				}
+			}
+
+			.work-layout-line {
+				background: #a9a9a9;
+				width: 1px;
+				height: 20px;
+				margin: 0 23px;
+			}
+
+			.work-layout-project {
+				display: flex;
+				align-items: center;
+				color: $--color-common;
+				cursor: pointer;
+
+				span {
+					font-size: 13px;
+					margin-right: 5px;
+				}
+
+				.iconfont {
+					transition: all 300ms;
+				}
+
+				.dropdown-icon {
+					transform: rotate(180deg);
+				}
+			}
+		}
+	}
+
+	.user-dropdown.el-dropdown-menu.el-popper {
+		width: 180px;
+		border-radius: 4px;
+		margin-top: 10px;
+
+		.el-dropdown-menu__item {
+			padding: 8px 40px 8px 16px;
+			margin: 2px 0;
+		}
+
+		.el-dropdown-menu__item:first-child {
+			background: $--color-background-hover;
+
+		}
+	}
+
+	.project-dropdown.el-dropdown-menu.el-popper {
+		border-radius: 4px;
+		margin-top: 17px;
+
+		.el-dropdown-menu__item {
+			padding: 8px 40px 8px 16px;
+			margin: 2px 0;
+		}
+	}
+
+	.user-drawer {
+
+		.el-drawer.ltr,
+		.el-drawer.rtl {
+			top: 52px;
+			height: auto;
+		}
+	}
+</style>

+ 155 - 0
virgo.wzfrontend/console/src/layout/components/userDetail.vue

@@ -0,0 +1,155 @@
+<template>
+	<div class="hui-flex">
+		<div class="hui-flex-box">
+			<div class="user-info">
+				<div class="user-info-avatar">
+					<div class="user-info-img">
+						<avatar :user="user"></avatar>
+					</div>
+					<div class="user-info-text">
+						<div class="user-info-name">{{user.name}}</div>
+						<div class="user-info-sub">项目经理</div>
+					</div>
+				</div>
+				<el-tabs v-model="activeName">
+					<el-tab-pane label="基本信息" name="first"></el-tab-pane>
+					<el-tab-pane label="工作信息" name="second"></el-tab-pane>
+				</el-tabs>
+				<div class="user-info-list" v-if="activeName === 'first'">
+					<div class="user-info-item">
+						<div class="user-info-label">姓名</div>
+						<div class="user-info-value">{{user.name}}</div>
+					</div>
+					<div class="user-info-item">
+						<div class="user-info-label">性别</div>
+						<div class="user-info-value">{{user.sex == 'M'?'男':'女'}}</div>
+					</div>
+					<div class="user-info-item">
+						<div class="user-info-label">手机号</div>
+						<div class="user-info-value">{{user.phone}}</div>
+					</div>
+					<div class="user-info-item">
+						<div class="user-info-label">邮箱</div>
+						<div class="user-info-value">{{user.email}}</div>
+					</div>
+				</div>
+				<div class="user-info-list" v-if="activeName === 'second'">
+					<div class="user-info-item">
+						<div class="user-info-label">岗位名称</div>
+						<div class="user-info-value">项目经理</div>
+					</div>
+					<div class="user-info-item">
+						<div class="user-info-label">公司部门</div>
+						<div class="user-info-value">智慧城市事业部</div>
+					</div>
+					<div class="user-info-item">
+						<div class="user-info-label">入职时间</div>
+						<div class="user-info-value">{{user.operateUserInfo.entryDate || '-'}}</div>
+					</div>
+					<div class="user-info-item">
+						<div class="user-info-label">空间定位</div>
+						<div class="user-info-value">
+							{{user.operateUserInfo.projectItemTargetRoomName || user.operateUserInfo.projectItemTargetName || user.operateUserInfo.projectItemName || '-'}}
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+		<div class="hui-drawer-submit">
+			<el-button size="medium" type="primary" @click="visible = true">编辑基本信息</el-button>
+		</div>
+		<el-dialog title="编辑基本信息" :visible.sync="visible" width="900px" :append-to-body="true">
+			<user-update v-if="visible" :user="user" @callback="callback"></user-update>
+		</el-dialog>
+	</div>
+</template>
+
+<script>
+	import {
+		getOperationUserInfo,
+		getUserInfo
+	} from '@/httpApi/loginRegister'
+	import avatar from '@/components/common/avatar'
+	import userUpdate from './userUpdate'
+	export default {
+		data() {
+			return {
+				activeName: 'first',
+				user: {
+					operateUserInfo: {}
+				},
+				visible: false
+			}
+		},
+		created() {
+			this.init();
+		},
+		methods: {
+			init() {
+				getUserInfo().then(res => {
+					if (res.state) {
+						this.user = res.data;
+						if (!this.user.operateUserInfo) this.user['operateUserInfo'] = {};
+						this.$store.dispatch('app/changeUser', this.user);
+					}
+				});
+			},
+			callback(type) {
+				this.visible = false;
+				if (type === 'init') this.init();
+			}
+		},
+		components: {
+			avatar,
+			userUpdate
+		},
+	}
+</script>
+
+<style lang="scss">
+	.user-info {
+		height: 100%;
+		width: 100%;
+		display: flex;
+		flex-direction: column;
+		padding: 20px;
+
+		.user-info-list {
+			flex: 1;
+			height: 0;
+			overflow-y: auto;
+
+			.user-info-item {
+				margin-bottom: 20px;
+
+				.user-info-label {
+					font-size: 12px;
+					opacity: 0.6;
+					margin-bottom: 5px;
+				}
+			}
+		}
+
+		.user-info-avatar {
+			display: flex;
+			align-items: center;
+			margin-bottom: 20px;
+
+			.user-info-img {
+				width: 45px;
+				height: 45px;
+				overflow: hidden;
+				border-radius: 50%;
+				margin-right: 16px;
+			}
+
+			.user-info-text {
+				.user-info-sub {
+					font-size: 12px;
+					opacity: 0.6;
+					margin-top: 5px;
+				}
+			}
+		}
+	}
+</style>

+ 66 - 0
virgo.wzfrontend/console/src/layout/components/userUpdate.vue

@@ -0,0 +1,66 @@
+<template>
+	<div class="hui-flex hui-dialog">
+		<div class="hui-flex-box hui-dialog-content">
+			<el-form ref="userForm" :model="userForm" label-position="top">
+				<el-form-item label="姓名" prop="name">
+					<el-input v-model="userForm.name"></el-input>
+				</el-form-item>
+				<el-form-item label="手机" prop="phone">
+					<el-input v-model="userForm.phone" disabled></el-input>
+				</el-form-item>
+				<el-form-item label="性别" prop="sex">
+					<el-select v-model="userForm.sex" placeholder="请选择性别">
+						<el-option label="男" value="M"></el-option>
+						<el-option label="女" value="W"></el-option>
+					</el-select>
+				</el-form-item>
+				<el-form-item label="邮箱" prop="email">
+					<el-input v-model="userForm.email" placeholder="请输入邮箱地址"></el-input>
+				</el-form-item>
+			</el-form>
+		</div>
+		<div class="hui-dialog-submit">
+			<el-button size="medium" @click="$emit('callback')">取 消</el-button>
+			<el-button size="medium" type="primary" @click="submit">保 存</el-button>
+		</div>
+	</div>
+</template>
+
+<script>
+	import {
+		updateUserDetails
+	} from '@/httpApi/loginRegister'
+	export default {
+		props: ['user'],
+		data() {
+			return {
+				userForm: {
+					name: '',
+					sex: '',
+					phone: '',
+					email: ''
+				}
+			}
+		},
+		created() {
+			this.userForm = JSON.parse(JSON.stringify(this.user));
+		},
+		methods: {
+			submit() {
+				this.userForm['id'] = this.userForm.userId;
+				updateUserDetails(this.userForm).then(res => {
+					if (res.state) {
+						this.$message.success('操作成功');
+						this.$emit('callback', 'init');
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.user-update {
+		padding: 10px;
+	}
+</style>

+ 379 - 0
virgo.wzfrontend/console/src/layout/loginRegister.vue

@@ -0,0 +1,379 @@
+<template>
+	<div class="login-register">
+		<div class="login-register-box">
+			<div class="title">
+				<div class="title-logo">
+					<img src="https://file-node.oss-cn-shanghai.aliyuncs.com/youji/3156449b8a1a4874981b2a76d5947721"
+						alt="logo.png">
+					<div>
+						<div class="title-name">有极物业管理平台</div>
+						<div class="title-sub-name">SMART BUILDING ASSET OPERATION PLATFORM</div>
+					</div>
+				</div>
+			</div>
+			<div class="content">
+				<div class="content-left">
+					<div class="content-title">
+						<div class="sub-title">有极物业管理平台</div>
+						<div class="small-title">
+							<span>运营维护</span>
+							<span class="line"></span>
+							<span>招商引资</span>
+						</div>
+					</div>
+					<div class="content-image"></div>
+				</div>
+				<div class="content-right">
+					<transition name="slide-fade" mode="out-in">
+						<router-view :key="key" />
+					</transition>
+				</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+
+<script>
+	export default {
+		name: 'login',
+		data() {
+			return {};
+		},
+		created() {},
+		methods: {},
+		computed: {
+			key() {
+				return this.$route.path;
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+	.login-register {
+		width: 100%;
+		height: 100%;
+		background: url(https://file-node.oss-cn-shanghai.aliyuncs.com/youji/8ead21d2c7464ae99745e93f5a17e4d3) no-repeat;
+		background-size: 100% 100%;
+		overflow: auto;
+
+		.login-register-box {
+			width: 100%;
+			height: 100%;
+			display: flex;
+			flex-direction: column;
+			min-width: 1300px;
+			min-height: 800px;
+		}
+
+		.title {
+			height: 64px;
+			background: rgba(255, 255, 255, 0.36);
+			box-shadow: 0px 0px 20px 0px rgba(0, 0, 0, 0.25);
+			padding-left: 46px;
+			display: flex;
+			align-items: center;
+
+			.title-logo {
+				width: 245px;
+				height: 34px;
+				margin-right: 74px;
+				display: flex;
+				align-items: center;
+				color: #484B50;
+			}
+
+			.title-sub-name {
+				font-size: 12px;
+				transform: scale(0.68) translateX(-66px);
+				width: 282px;
+				opacity: 0.75;
+			}
+
+			.title-name {
+				font-family: hanyiyaku;
+				font-size: 16px;
+				line-height: 22px;
+			}
+
+			.title-logo img {
+				width: 34px;
+				height: 34px;
+				margin-right: 10px;
+				border-radius: 5px;
+			}
+		}
+
+		.content {
+			flex: 1;
+			height: 0;
+			width: 100%;
+			overflow: auto;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+
+			.content-image {
+				width: 640px;
+				height: 440px;
+				background: url(https://file-node.oss-cn-shanghai.aliyuncs.com/youji/2fdedc8660e146b7bb003ce85dedea5f) no-repeat;
+				background-size: 100% 100%;
+			}
+
+			.content-left {
+				width: 910px;
+				display: flex;
+				flex-direction: column;
+				padding-left: 90px;
+			}
+
+			.content-right {
+				width: 400px;
+				display: flex;
+				align-items: center;
+			}
+
+			.content-title {
+				margin-bottom: 64px;
+			}
+
+			.sub-title {
+				font-weight: 600;
+				font-size: 31px;
+				color: #484B50;
+				line-height: 44px;
+				text-align: left;
+				font-style: normal;
+				margin-bottom: 10px;
+			}
+
+			.small-title {
+				font-weight: 400;
+				font-size: 16px;
+				color: #333E4D;
+				line-height: 22px;
+				text-align: left;
+				font-style: normal;
+				display: flex;
+				align-items: center;
+
+				.line {
+					margin: 0 20px;
+					width: 1px;
+					height: 16px;
+					background: #CBE0FF;
+				}
+			}
+		}
+	}
+
+	.login-box {
+		width: 440px;
+		background: #FFFFFF;
+		box-shadow: 0px 4px 16px 0px rgba(164, 178, 203, 0.15);
+		border-radius: 8px;
+		border: 0px solid #FFFFFF;
+
+		.get-code-btn {
+			position: absolute;
+			font-size: 16px;
+			color: #3371FF;
+			height: 52px;
+			line-height: 52px;
+			top: 0;
+			right: 16px;
+			padding: 0 16px;
+			cursor: pointer;
+		}
+
+		.get-code-btn-disabled {
+			color: #BEBEBE;
+		}
+
+		.login-title {
+			padding: 62px 52px 48px 52px;
+		}
+
+		.register {
+			text-align: center;
+			color: #333E4D;
+			line-height: 20px;
+			padding: 20px;
+
+			span {
+				cursor: pointer;
+				color: $--color-primary;
+			}
+		}
+
+		.login-title-value {
+			font-weight: 600;
+			font-size: 28px;
+			color: #333E4D;
+			line-height: 40px;
+			text-align: left;
+			font-style: normal;
+			margin-bottom: 16px;
+		}
+
+		.login-title-line {
+			width: 80px;
+			height: 5px;
+			background: #E3E7EE;
+		}
+
+		.login-form {
+			padding: 0 52px;
+			border-bottom: 1px solid #EDEFF2;
+
+			input:-webkit-autofill {
+				box-shadow: 0 0 0 30px #fff inset !important;
+				-webkit-text-fill-color: #333E4D !important;
+				background-color: #fff !important;
+				transition: background-color 5000s ease-in-out 0s;
+			}
+
+			.el-form {
+				display: block;
+
+				.el-form-item {
+					width: 100%;
+					padding: 0;
+					margin-bottom: 28px;
+					position: relative;
+				}
+
+				.el-input__inner {
+					border-radius: 4px;
+					border: 1px solid #EDEFF2;
+					background: transparent;
+					color: #333E4D;
+					padding: 15px 15px 15px 63px;
+					height: 52px;
+					line-height: 52px;
+					font-size: 16px;
+				}
+
+				.el-form-item.is-error .el-input__inner,
+				.el-form-item.is-error .el-input__inner:focus,
+				.el-form-item.is-error .el-textarea__inner,
+				.el-form-item.is-error .el-textarea__inner:focus {
+					border-color: $--color-red;
+				}
+
+				.el-form-item__error {
+					color: $--color-red;
+				}
+
+				.el-input__inner::placeholder,
+				.el-range-input::placeholder,
+				.el-textarea__inner::placeholder {
+					color: $--color-common;
+				}
+
+				.el-input__icon,
+				.el-range-separator {
+					line-height: 52px;
+					font-size: 16px;
+				}
+
+				.el-input__prefix {
+					left: 16px;
+				}
+
+				.el-input__prefix::before {
+					content: '';
+					top: 16px;
+					right: -16px;
+					height: 21px;
+					width: 1px;
+					background-color: #EDEFF2;
+					position: absolute;
+				}
+
+				.el-input__icon.iconfont {
+					font-size: 20px;
+					color: #4d5e79;
+				}
+
+				.el-input__icon.huifont-mima {
+					opacity: 0.95;
+					margin-left: 2px;
+				}
+			}
+
+			.forget-box {
+				width: 100%;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				margin-bottom: 50px;
+
+				.forget {
+					color: #5D6C82;
+					cursor: pointer;
+				}
+
+				.forget:hover {
+					color: $--color-primary;
+				}
+
+				.el-checkbox__inner {
+					border-color: #EDEFF2;
+				}
+
+				.el-checkbox__label {
+					color: #333E4D;
+					padding-left: 8px;
+				}
+
+				.el-checkbox.is-checked .el-checkbox__inner {
+					border-color: $--color-primary;
+				}
+
+				.el-checkbox:hover {
+					.el-checkbox__label {
+						color: $--color-primary;
+					}
+
+					.el-checkbox__inner {
+						border-color: $--color-primary;
+					}
+				}
+
+
+			}
+
+			.el-button {
+				width: 100%;
+				margin-bottom: 60px;
+				font-weight: 600;
+				font-size: 20px;
+				color: #FFFFFF;
+				line-height: 28px;
+			}
+		}
+
+		.image-item {
+			.el-form-item__content {
+				display: flex;
+			}
+
+			.el-input {
+				width: 190px;
+				margin-right: 12px;
+			}
+
+			.code-image {
+				width: 131px;
+				height: 50px;
+				cursor: pointer;
+			}
+		}
+	}
+
+	.login-register::-webkit-scrollbar-thumb {
+		background: #d4d4d4;
+	}
+</style>

+ 337 - 7
virgo.wzfrontend/console/src/layout/work.vue

@@ -1,8 +1,338 @@
-<template>
-</template>
-
-<script>
-</script>
-
-<style>
+<template>
+	<div class="work-layout">
+		<top-nav></top-nav>
+		<div :class="isCollapse ? 'small-main work-layout-main':'work-layout-main'">
+			<div class="app-main-box">
+				<el-menu router :default-active="$route.path" :collapse="isCollapse" :collapse-transition="false">
+					<sub-menu :menuData="menuList" :menuIndex="1"></sub-menu>
+				</el-menu>
+			</div>
+			<div class="app-main-button" @click="set">
+				<i class="iconfont huifont-shezhi"></i>
+				<div>设置后台</div>
+			</div>
+			<div class="work-layout-main-tag" @click="isCollapse = !isCollapse">
+				<i :class="'iconfont '+ (isCollapse ? 'huifont-xiala-right':'huifont-xiala-left')"></i>
+			</div>
+		</div>
+		<bread-crumb :class="isCollapse ? 'small-crumb':''"></bread-crumb>
+		<div :class="isCollapse ? 'small-content work-layout-content':'work-layout-content'">
+			<transition name="slide-fade">
+				<router-view :key="key" />
+			</transition>
+		</div>
+	</div>
+</template>
+
+<script>
+	import subMenu from './components/subMenu'
+	import topNav from './components/topNav'
+	import breadCrumb from './components/breadCrumb'
+	export default {
+		data() {
+			return {
+				menuList: [],
+				isCollapse: false
+			}
+		},
+		created() {
+			this.init();
+		},
+		methods: {
+			init() {
+				this.menuList = this.$store.getters.menuData.filter(node => node.title !== '系统设置');
+			},
+			set() {
+				let list = this.$store.getters.menuData.filter(node => node.title === '系统设置');
+				if (list.length === 0) return this.$message.warning('您暂无系统设置权限');
+				if (list[0].children.length === 0) return this.$message.warning('您暂无系统设置权限');
+				console.log(list[0].children[0].index);
+				this.$router.push(list[0].children[0].index);
+			}
+		},
+		components: {
+			subMenu,
+			topNav,
+			breadCrumb
+		},
+		computed: {
+			key() {
+				let list = this.$store.getters.menuData.filter(node => node.title === '系统设置');
+				if (this.$route.path.indexOf('/work/system') > -1) return list[0].children[0].index;
+				return this.$route.path;
+			}
+		},
+	}
+</script>
+
+<style lang="scss">
+	.work-layout {
+		width: 100%;
+		height: 100%;
+		overflow: hidden;
+		position: relative;
+		background: $--background;
+
+		.work-layout-main {
+			position: fixed;
+			left: 0;
+			top: 53px;
+			width: 164px;
+			bottom: 0;
+			background: $--box-background;
+			padding: 8px 8px 0px 8px;
+			box-sizing: border-box;
+			display: flex;
+			flex-direction: column;
+			transition: all 0.4s;
+			z-index: 99;
+
+			.app-main-button {
+				border-top: 1px solid #374156;
+				padding: 16px 13px;
+				display: flex;
+				cursor: pointer;
+				margin-top: 12px;
+				align-items: center;
+
+				i.huifont-shezhi {
+					font-size: 24px;
+					margin-right: 7px;
+				}
+
+				div {
+					flex: 1;
+					width: 0;
+					overflow: hidden;
+					font-weight: 400;
+					word-spacing: break-all;
+					height: 20px;
+				}
+			}
+
+			.menu-title {
+				font-weight: 400;
+			}
+
+			.el-menu--collapse {
+
+				.el-submenu__icon-arrow,
+				.menu-title {
+					display: none;
+				}
+			}
+
+			.work-layout-main-tag {
+				position: absolute;
+				top: 0;
+				right: -24px;
+				width: 24px;
+				height: 24px;
+				background: rgba(255, 255, 255, 0.1);
+				border-radius: 0px 24px 24px 0px;
+				line-height: 24px;
+				font-size: 12px;
+				text-align: center;
+				cursor: pointer;
+				z-index: 99;
+			}
+
+			.app-main-box {
+				flex: 1;
+				height: 0;
+				overflow-y: auto;
+				overflow-x: hidden;
+				-ms-overflow-style: none;
+				/* 隐藏 IE 中的滚动条 */
+				scrollbar-width: none;
+				/* 隐藏 Firefox 中的滚动条 */
+			}
+
+			.app-main-box::-webkit-scrollbar {
+				width: 0;
+				/* 隐藏滚动条 */
+			}
+
+			.el-menu {
+				width: 100%;
+				height: 100%;
+				background: $--box-background;
+				border-right: none;
+
+				.el-icon-arrow-down {
+					font-family: "iconfont" !important;
+					font-size: 16px;
+				}
+
+				.el-icon-arrow-down::before {
+					content: "\e72d";
+				}
+
+				.el-menu-item,
+				.el-submenu__title {
+					border-radius: 5px;
+					height: 48px;
+					line-height: 46px;
+					font-size: 14px;
+					min-width: auto;
+					color: $--color-common;
+					margin: 3px 0;
+					padding-right: 10px;
+
+					i {
+						color: $--color-common;
+					}
+
+					i.icon {
+						font-size: 24px;
+						margin-right: 8px;
+					}
+
+					&:hover,
+					&.is-active,
+					&:focus {
+						background-color: $--color-primary;
+						color: #fff;
+
+						i,
+						span {
+							color: #fff;
+						}
+					}
+				}
+
+				.el-submenu__title {
+					.el-submenu__icon-arrow {
+						right: 10px;
+					}
+				}
+
+				.menu-index-1 {
+
+					.el-menu-item,
+					.el-submenu__title {
+						padding-left: 12px !important;
+					}
+				}
+
+				.menu-index-2 {
+
+					.el-menu-item,
+					.el-submenu__title {
+						padding-left: 40px !important;
+					}
+				}
+
+				.menu-index-3 {
+
+					.el-menu-item,
+					.el-submenu__title {
+						padding-left: 50px !important;
+					}
+				}
+
+				.menu-index-3 {
+
+					.el-menu-item,
+					.el-submenu__title {
+						padding-left: 60px !important;
+					}
+				}
+
+				.menu-index-4 {
+
+					.el-menu-item,
+					.el-submenu__title {
+						padding-left: 70px !important;
+					}
+				}
+
+				.menu-index-5 {
+
+					.el-menu-item,
+					.el-submenu__title {
+						padding-left: 80px !important;
+					}
+				}
+			}
+		}
+
+		.small-main {
+			width: 64px;
+			padding: 8px 8px 0px 8px;
+		}
+
+		.work-layout-content {
+			position: absolute;
+			top: 89px;
+			left: 176px;
+			right: 12px;
+			bottom: 12px;
+			background: $--box-background;
+			transition: left 0.4s;
+
+			.slide-fade-enter-active {
+				transition: all 0.1s ease;
+			}
+
+			.slide-fade-leave-active {
+				transition: all 0.2s cubic-bezier(1, 0.5, 0.8, 1);
+			}
+
+			.slide-fade-enter,
+			.slide-fade-leave-to {
+				transform: translateX(10px);
+				opacity: 0;
+			}
+		}
+
+		.small-content {
+			left: 76px;
+		}
+
+		.bread-crumb {
+			position: absolute;
+			top: 60px;
+			left: 176px;
+			right: 12px;
+			transition: left 0.4s;
+			z-index: 8;
+		}
+
+		.small-crumb {
+			left: 76px;
+		}
+	}
+
+	.el-menu--vertical {
+		.el-menu--popup {
+			min-width: 164px;
+		}
+
+		.el-menu {
+			background: $--color-background;
+			border-radius: 8px;
+
+			.el-menu-item,
+			.el-submenu__title {
+				color: $--color-common;
+				height: 48px;
+				line-height: 48px;
+			}
+
+			.el-menu-item:hover,
+			.el-menu-item:focus,
+			.el-submenu__title:hover,
+			.el-submenu__title:focus {
+				background: $--color-background-hover;
+				border-radius: 4px;
+			}
+
+			.menu-index-2 {
+				padding: 0 8px;
+				height: 48px;
+				line-height: 48px;
+			}
+		}
+	}
 </style>

+ 9 - 1
virgo.wzfrontend/console/src/main.js

@@ -11,6 +11,12 @@ Vue.config.productionTip = false;
 import loading from './loading/loading';
 Vue.use(loading);
 
+import empty from './components/common/empty'
+Vue.component('empty', empty)
+
+import avatar from './components/common/avatar'
+Vue.component('avatar', avatar)
+
 Vue.prototype.$confirm = (title, callback) => {
 	return ElementUI.MessageBox.confirm(title, '红信提示', {
 		confirmButtonText: '确 定',
@@ -19,7 +25,9 @@ Vue.prototype.$confirm = (title, callback) => {
 		cancelButtonText: '取 消',
 		type: 'warning'
 	}).then(callback).catch(() => {});
-};
+};
+//router拦截器
+import './uitls/permission'
 new Vue({
 	router,
 	store,

+ 2 - 1
virgo.wzfrontend/console/src/router/index.js

@@ -1,6 +1,7 @@
 import Vue from 'vue'
 import Router from 'vue-router'
 import workRouter from './work'
+import loginRouter from './loginRegister'
 
 Vue.use(Router)
 const originalPush = Router.prototype.push;
@@ -8,7 +9,7 @@ Router.prototype.push = function push(location) {
 	return originalPush.call(this, location).catch(err => err);
 };
 export default new Router({
-	routes: [workRouter, { //404
+	routes: [workRouter, loginRouter, { //404
 			path: '/404',
 			component: () => import('@/views/error/404'),
 		},

+ 1 - 8
virgo.wzfrontend/console/src/router/loginRegister.js

@@ -10,14 +10,7 @@ const loginRegisterRouter = {
 		meta: {
 			title: '登录'
 		}
-	}, {
-		path: 'register',
-		component: () => import('@/views/register'),
-		name: '注册',
-		meta: {
-			title: '注册'
-		}
 	}]
-}
+}
 
 export default loginRegisterRouter;

+ 16 - 0
virgo.wzfrontend/console/src/router/modules/space.js

@@ -0,0 +1,16 @@
+const space = [{
+	path: 'space/project',
+	component: () => import('@/views/work/space/project/list'),
+	name: '项目列表',
+	meta: {
+		title: '项目列表'
+	}
+}, {
+	path: 'space/set',
+	component: () => import('@/views/work/space/set/list'),
+	name: '空间设置',
+	meta: {
+		title: '空间设置'
+	}
+}]
+export default space;

+ 13 - 0
virgo.wzfrontend/console/src/router/modules/system.js

@@ -0,0 +1,13 @@
+const system = [{
+	path: 'system',
+	component: () => import('@/views/system'),
+	children: [{
+		path: 'main',
+		component: () => import('@/views/system/main/list'),
+		name: '菜单管理',
+		meta: {
+			title: '菜单管理'
+		}
+	}]
+}]
+export default system;

+ 2 - 9
virgo.wzfrontend/console/src/router/work.js

@@ -1,20 +1,13 @@
 import Layout from '@/layout/work'
 
 const modulesFiles = require.context('./modules', true, /\.js$/);
-let child = [{
-	path: '',
-	component: () => import('@/views/work'),
-	name: '工作台',
-	meta: {
-		title: '工作台'
-	}
-}];
+let child = [];
 modulesFiles.keys().reduce((modules, modulePath) => {
 	const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
 	const value = modulesFiles(modulePath);
 	child = child.concat(value.default);
 }, {})
-
+console.log(child);
 const workRouter = {
 	path: '/',
 	component: Layout,

+ 1 - 2
virgo.wzfrontend/console/src/store/getters.js

@@ -3,8 +3,7 @@ const getters = {
 	user: state => state.app.user, //用户基本信息
 	menuData: state => state.app.menuData, //用户菜单
 	organization: state => state.app.organization, //所属组织信息
-	project: state => state.projectBase.project, //项目
+	project: state => state.projectBase.project || {}, //项目
 	config: state => state.app.config, //url配置信息
-	contextData: state => state.projectBase.contextData //文档使用的基础数据
 }
 export default getters

+ 2 - 20
virgo.wzfrontend/console/src/store/modules/projectBase.js

@@ -3,38 +3,20 @@
  * 	
  */
 const state = {
-	projectItem: [],
-	project: {},
-	contextData: {}
+	project: {}
 }
 
 const mutations = {
-	CHANGE_PROJECTITEM: (state, projectItem) => {
-		state.projectItem = projectItem;
-	},
 	CHANGE_PROJECT: (state, project) => {
 		state.project = project;
-	},
-	CHANGE_CONTEXTDATA: (state, contextData) => {
-		state.contextData = contextData;
 	}
 }
 
 const actions = {
-	changeProjectItem({
-		commit,
-	}, projectItem) {
-		commit('CHANGE_PROJECTITEM', projectItem);
-	},
 	changeProject({
 		commit,
 	}, project) {
 		commit('CHANGE_PROJECT', project);
-	},
-	changeContextData({
-		commit,
-	}, contextData) {
-		commit('CHANGE_CONTEXTDATA', contextData);
 	}
 }
 
@@ -43,4 +25,4 @@ export default {
 	state,
 	mutations,
 	actions
-}
+}

File diff suppressed because it is too large
+ 10110 - 0
virgo.wzfrontend/console/src/uitls/map.js


+ 4 - 4
virgo.wzfrontend/console/src/uitls/permission.js

@@ -14,10 +14,10 @@ import Vue from 'vue'
 NProgress.configure({
 	showSpinner: false
 })
-const baseUrl = ['/', '/401', '/404', '/loginRegister/login', '/loginRegister/register'];
+const baseUrl = ['/', '/401', '/404', '/loginRegister/login', '/system/main'];
 
 const testBaseUrl = (path) => { //判断公共路由
-	let nowBaseUrl = ['/loginRegister/login', '/loginRegister/register'].filter((item) => {
+	let nowBaseUrl = ['/loginRegister/login'].filter((item) => {
 		return (item == path && item != '/')
 	})
 	return nowBaseUrl.length == 0;
@@ -50,9 +50,9 @@ router.beforeEach((to, from, next) => {
 	/* 判断是否有权限 */
 	if (testComment(to.path)) return next('/401');
 	/* 无项目时跳转项目列表页面 */
-	if (getToken() && localStorage.getItem('projectId') == 0 && to.path !== '/work/people/project') {
+	if (getToken() && localStorage.getItem('projectId') == 0 && to.path !== '/space/project') {
 		tip('暂无项目,请先添加项目');
-		return next('/work/people/project');
+		return next('/space/project');
 	}
 	NProgress.start();
 	next();

+ 221 - 0
virgo.wzfrontend/console/src/views/login/index.vue

@@ -0,0 +1,221 @@
+<template>
+	<div class="login-box">
+		<div class="login-title">
+			<div class="login-title-value">登录有极</div>
+			<div class="login-title-line"></div>
+		</div>
+		<div class="login-form">
+			<el-form :model="loginForm" :rules="loginRules" status-icon ref="loginForm" label-position="left">
+				<el-form-item prop="phone">
+					<el-input type="text" prefix-icon="iconfont huifont-shoujihao" v-model="loginForm.phone"
+						placeholder="手机号" maxlength="11">
+					</el-input>
+				</el-form-item>
+				<el-form-item prop="code" class="image-item">
+					<el-input type="text" prefix-icon="iconfont huifont-tuxingyanzhengma" v-model="loginForm.code"
+						placeholder="图片验证码" maxlength="4"></el-input>
+					<img v-if="codeImg" :src="codeImg" alt="图片验证码" class="code-image" @click="imgCodeFunc">
+				</el-form-item>
+				<el-form-item prop="phoneCode" class="phone-code">
+					<el-input type="number" prefix-icon="iconfont huifont-duanxinyanzhengma"
+						v-model="loginForm.phoneCode" placeholder="短信验证码"
+						oninput="if(value.length > 6) value=value.slice(0, 6)"></el-input>
+					<div :class="codeName === '获取验证码'?'get-code-btn' : 'get-code-btn-disabled get-code-btn'"
+						@click="getPhoneCode">
+						{{codeName}}
+					</div>
+				</el-form-item>
+			</el-form>
+			<el-button type="primary" @click="loginSubmit" :loading="loginLoading">登录</el-button>
+		</div>
+	</div>
+</template>
+
+<script>
+	import {
+		login,
+		getUserInfo,
+		selectProject,
+		selectOrangaized,
+		getOrganizedProjectList,
+		getImgCode,
+		sendPhoneCode
+	} from '@/httpApi/loginRegister';
+	import {
+		setToken,
+		setComment
+	} from '@/uitls/auth';
+	export default {
+		data() {
+			return {
+				loginForm: {
+					phone: '18888888888',
+					code: '8',
+					phoneCode: '888888'
+				},
+				loginLoading: false,
+				codeImg: '',
+				codeName: '获取验证码', //获取验证码text
+				isDisabled: false, //获取验证码按钮状态
+				loginRules: {
+					code: [{
+						required: true,
+						message: '请输入图片验证码',
+						trigger: 'blur'
+					}],
+					phone: [{
+						required: true,
+						message: '请输入手机号',
+						trigger: 'blur'
+					}, {
+						validator: (rule, value, callback) => {
+							if (!/^1[123456789]\d{9}$/.test(value)) {
+								callback(new Error("请输入正确的手机号"));
+							} else {
+								callback();
+							}
+						},
+						trigger: 'blur'
+					}],
+					phoneCode: [{
+						required: true,
+						message: '请输入短信验证码',
+						trigger: 'blur'
+					}]
+				},
+			};
+		},
+		created() {
+			this.imgCodeFunc();
+			if (this.$store.getters.codeNumber != 60) this.codeReset();
+		},
+		methods: {
+			imgCodeFunc() {
+				getImgCode().then(res => {
+					if (res.state) {
+						this.codeImg = res.data.pngBase64;
+					}
+				})
+			},
+			getPhoneCode() {
+				if (this.isDisabled) return;
+				this.$refs.loginForm.validateField('phone', valid => {
+					if (!valid) {
+						this.$refs.loginForm.validateField('code', valid => {
+							if (!valid) {
+								sendPhoneCode(this.loginForm.phone, this.loginForm.code).then(res => {
+									if (res.state) {
+										this.codeReset();
+										this.$message.success('发送成功');
+									}
+								})
+							}
+						})
+					}
+				})
+			},
+			codeReset() {
+				//重置获取验证码倒计时
+				let codeNumber = this.$store.getters.codeNumber;
+				codeNumber--;
+				this.handleCode(codeNumber);
+				let codeRestFn = setInterval(() => {
+					codeNumber--;
+					this.handleCode(codeNumber);
+					if (codeNumber == 0) clearInterval(codeRestFn); //停止
+				}, 1000);
+			},
+			handleCode(codeNumber) {
+				//code操作
+				this.codeName = codeNumber == 0 ? '获取验证码' : '重新获取' + codeNumber;
+				this.isDisabled = codeNumber == 0 ? false : true;
+				this.$store.dispatch('loginRegister/changeCodeNumber', codeNumber == 0 ? 60 : codeNumber);
+			},
+			loginSubmit() {
+				if (this.loginLoading) return;
+				this.loginLoading = true;
+				this.$refs['loginForm'].validate(valid => {
+					if (!valid) return this.loginLoading = false;
+					this.loginFunc();
+				})
+			},
+			loginFunc() {
+				let postData = {
+					phone: this.loginForm.phone,
+					phoneCode: this.loginForm.phoneCode
+				}
+				login(postData).then(res => {
+					if (res.state) {
+						setToken(res.data.token);
+						getUserInfo().then(res => {
+							if (res.state) {
+								let organized = this.testOrganized(res.data);
+								if (!organized) return this.loginLoading = false;
+								this.selectOrganized(organized);
+								this.$store.dispatch('app/changeOrganization', organized);
+								//vuex仓库存储user基本信息
+								let user = res.data;
+								getOrganizedProjectList(organized.id).then(res => {
+									if (res.state) {
+										if (!res.data || res.data.length == 0) {
+											this.$store.dispatch('projectBase/changeProject', {});
+											this.$store.dispatch('app/changeUser', user);
+											return this.$router.push('/space/project');
+										}
+										let project = user.projectId === -1 ? res.data[0] : res
+											.data.filter(node => node.id == user.projectId)[0];
+										this.selectProject(project)
+									}
+								});
+							} else {
+								this.loginLoading = false;
+							}
+						})
+					} else {
+						this.loginLoading = false;
+					}
+				})
+			},
+			testOrganized(data) {
+				if (data.operateOrganizationList == 0) {
+					this.$message.warning('您暂未有组织,请联系组织管理员添加');
+					return false;
+				}
+				let organized = !data.organization ? data.organizationList[0] : data.organization;
+				if (organized.status === 0) {
+					this.$message.warning('您所属的组织信息暂未审核通过');
+					return false;
+				}
+				return organized;
+			},
+			selectProject(data) {
+				data.projectItemList = data.projectItemList || [];
+				data.projectItemList.sort((a, b) => {
+					return a.id - b.id;
+				});
+				this.project = data;
+				this.$store.dispatch('projectBase/changeProject', data);
+				localStorage.setItem('projectId', data.id);
+				selectProject(data.id).then(res => {
+					this.loginLoading = false;
+					if (res.state) {
+						let user = res.data;
+						if (!user.operateUserInfo) user['operateUserInfo'] = {};
+						this.$store.dispatch('app/changeUser', user);
+						this.$store.dispatch('app/changeMenuData', user.resource ? JSON.parse(user.resource) : []);
+						setComment(user.menu ? user.menu : JSON.stringify([]));
+						this.$router.push('/');
+						this.$message.success('登录成功');
+					}
+				});
+			},
+			selectOrganized(data) {
+				selectOrangaized(data)
+			}
+		}
+	};
+</script>
+
+<style lang="scss">
+
+</style>

+ 41 - 0
virgo.wzfrontend/console/src/views/system/index.vue

@@ -0,0 +1,41 @@
+<template>
+	<div class="hui-flex hui-content">
+		<div class="hui-content-title">
+			<div :class="'hui-title-item'+(key === item.index ?' active':'')" v-for="(item,index) in list"
+				:key="item.id" @click="linkTo(item.index)">
+				{{item.title}}
+			</div>
+		</div>
+		<div class="hui-flex-box">
+			<transition name="slide-fade">
+				<router-view :key="key" />
+			</transition>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				list: []
+			}
+		},
+		created() {
+			this.list = this.$store.getters.menuData.filter(node => node.title === '系统设置')[0].children;
+		},
+		methods: {
+			linkTo(url) {
+				if (this.key === url) return;
+				this.$router.push(url);
+			}
+		},
+		computed: {
+			key() {
+				return this.$route.path;
+			}
+		},
+	}
+</script>
+
+<style lang="scss"></style>

+ 154 - 0
virgo.wzfrontend/console/src/views/system/main/list.vue

@@ -0,0 +1,154 @@
+<template>
+	<div class="hui-flex">
+		<div class="hui-flex-box hui-flex hui-table">
+			<div class="hui-content-insert">
+				<el-button type="primary" size="medium" @click="insert(-1)">新增主菜单</el-button>
+			</div>
+			<div class="hui-flex-box">
+				<el-table :data="tableData" row-key="id" border height="100%">
+					<el-table-column prop="title" label="菜单名称" width="180">
+					</el-table-column>
+					<el-table-column prop="iconClass" label="菜单图标" width="180">
+					</el-table-column>
+					<el-table-column prop="index" label="菜单URL">
+					</el-table-column>
+					<el-table-column label="操作" width="180">
+						<template slot-scope="scope">
+							<div class="hui-table-operation">
+								<span class="table-operation" @click="insert(scope.row.id)">新增</span>
+								<span class="table-operation" @click="update(scope.row)">编辑</span>
+								<span class="table-operation" @click="deleteItem(scope.row.id)">删除</span>
+							</div>
+						</template>
+					</el-table-column>
+					<template slot="empty">
+						<empty description="暂无数据"></empty>
+					</template>
+				</el-table>
+			</div>
+		</div>
+		<el-dialog title="菜单" :visible.sync="dialogVisible" width="900px" :append-to-body="true">
+			<edit v-if="dialogVisible" :updateData="updateData" ref="mainForm" @callback="dialogVisible = false"
+				@sure="sure">
+			</edit>
+		</el-dialog>
+	</div>
+</template>
+
+<script>
+	import {
+		getMenuList,
+		insertMenu,
+		updateMenu
+	} from '@/httpApi/system'
+	import edit from '@/components/system/main/edit'
+	export default {
+		data() {
+			return {
+				tableData: [],
+				comment: [],
+				dialogVisible: false,
+				tableId: 1,
+				nowDataId: -1,
+				updateData: {},
+				menuData: {},
+				type: ''
+			}
+		},
+		created() {
+			this.init()
+		},
+		methods: {
+			init() {
+				getMenuList().then(res => {
+					if (res.state) {
+						if (!res.data || res.data.length === 0) return;
+						this.menuData = res.data[0];
+						this.tableData = JSON.parse(this.menuData.data);
+						this.comment = [];
+						this.testIndex(this.tableData);
+						this.testComment(this.tableData);
+					}
+				})
+			},
+			testIndex(tableData) {
+				for (let i = 0; i < tableData.length; i++) {
+					if (tableData[i].id + 1 > this.tableId) this.tableId = tableData[i].id + 1;
+					if (tableData[i].children) this.testIndex(tableData[i].children);
+				}
+			},
+			testComment(item, id, form) {
+				if (id == -1) return item.push(form);
+				if (this.type == 'delete') {
+					let index = item.findIndex(node => node.id == id);
+					if (index > -1) item.splice(index, 1);
+				}
+				for (let i = 0; i < item.length; i++) {
+					if (item[i].id == id) {
+						if (this.type == 'insert') {
+							if (!item[i].children) item[i].children = [];
+							item[i].children.push(form);
+						} else if (this.type == 'update') {
+							item[i] = form;
+						}
+					}
+					if (item[i].index && this.comment.filter(node => node == item[i].index).length == 0) this.comment.push(
+						item[i].index);
+					if (item[i].children) this.testComment(item[i].children, id, form);
+				}
+			},
+			insert(id) {
+				this.type = 'insert';
+				this.nowDataId = id;
+				this.updateData = {};
+				this.dialogVisible = true;
+			},
+			update(item) {
+				this.type = 'update';
+				this.nowDataId = item.id;
+				this.updateData = JSON.parse(JSON.stringify(item));
+				this.dialogVisible = true;
+			},
+			deleteItem(id) {
+				this.type = 'delete';
+				this.nowDataId = id;
+				this.updateData = {};
+				this.sure();
+			},
+			sure() {
+				let obj = JSON.parse(JSON.stringify(this.tableData));
+				this.comment = [];
+				this.testComment(obj, this.nowDataId, this.returnForm());
+				this.menuData.id ? updateMenu({
+					id: this.menuData.id,
+					data: JSON.stringify(obj),
+					comment: JSON.stringify(this.comment)
+				}).then(this.successFunc) : insertMenu({
+					data: JSON.stringify(obj),
+					comment: JSON.stringify(this.comment)
+				}).then(this.successFunc);
+			},
+			returnForm() {
+				if (this.type == 'delete') return {};
+				let form = this.$refs.mainForm.sureIncrease();
+				if (this.type == 'insert') form['id'] = this.tableId;
+				return form;
+			},
+			successFunc(res) {
+				if (res.state) {
+					this.$message({
+						type: 'success',
+						message: '操作成功'
+					})
+					this.init();
+					this.dialogVisible = false;
+				}
+			}
+		},
+		components: {
+			edit
+		},
+	}
+</script>
+
+<style lang="scss"></style>

+ 150 - 0
virgo.wzfrontend/console/src/views/work/space/project/list.vue

@@ -0,0 +1,150 @@
+<template>
+	<div class="hui-flex hui-content">
+		<div class="hui-content-title">
+			<div class="hui-title-item active">项目管理</div>
+		</div>
+		<div class="hui-flex-box hui-flex hui-table">
+			<div class="hui-content-insert">
+				<el-button type="primary" size="medium" @click="insertProject">新增项目</el-button>
+			</div>
+			<div class="hui-flex-box">
+				<el-table :data="tableData" row-key="id" border height="100%">
+					<el-table-column label="序号" width="50">
+						<template slot-scope="scope">
+							<div style="text-align: center;">{{scope.$index + 1}}</div>
+						</template>
+					</el-table-column>
+					<el-table-column label="项目名称" prop="name">
+					</el-table-column>
+					<el-table-column label="操作" width="150">
+						<template slot-scope="scope">
+							<div class="hui-table-operation">
+								<span class="table-operation" @click="lookProject(scope.row)">详情</span>
+								<span class="table-operation" @click="updateProject(scope.row)">编辑</span>
+								<span class="table-operation" @click="deleteProject(scope.row)">删除</span>
+							</div>
+						</template>
+					</el-table-column>
+					<template slot="empty">
+						<empty description="暂无数据"></empty>
+					</template>
+				</el-table>
+			</div>
+			<div class="hui-content-pagination">
+				<el-pagination :page-size="pageSize" :pager-count="9" layout="prev, pager, next" :total="totalCount"
+					@current-change="currentChange">
+				</el-pagination>
+			</div>
+		</div>
+		<el-dialog :title="isUpdate?'编辑':'新增'" :visible.sync="visible" width="900px" :append-to-body="true">
+			<edit v-if="visible" @callback="callback" :isUpdate="isUpdate" :detailId="detailId"></edit>
+		</el-dialog>
+		<el-drawer title="项目详情" :visible.sync="drawer" :size="400" :append-to-body="true">
+			<detail v-if="drawer" :detailId="detailId"></detail>
+		</el-drawer>
+
+	</div>
+</template>
+
+<script>
+	import {
+		getProjectListByPage,
+		deleteProjectById
+	} from '@/httpApi/work'
+	import edit from '@/components/work/space/project/edit'
+	import detail from '@/components/work/space/project/detail'
+	import {
+		selectProject
+	} from '@/httpApi/loginRegister'
+	import {
+		setComment
+	} from '@/uitls/auth';
+	export default {
+		data() {
+			return {
+				tableData: [],
+				currPage: 1,
+				pageSize: 10,
+				totalCount: 0,
+				visible: false,
+				detailId: '',
+				isUpdate: false,
+				drawer: false
+			}
+		},
+		created() {
+			this.init();
+		},
+		methods: {
+			init() {
+				getProjectListByPage({
+					currPage: this.currPage,
+					pageSize: this.pageSize,
+					operateOrganizationId: this.$store.getters.organization.id
+				}).then(res => {
+					if (res.state) {
+						this.tableData = res.data.dataList;
+						this.totalCount = res.data.totalCount;
+						if (this.$store.getters.project.id) return;
+						this.changeProject(this.tableData[0]);
+					}
+				})
+			},
+			changeProject(data) {
+				if (!data) return;
+				data.projectItemList = data.projectItemList || [];
+				data.projectItemList.sort((a, b) => {
+					return a.id - b.id;
+				});
+				selectProject(data.id).then(res => {
+					if (res.state) {
+						let user = res.data;
+						localStorage.setItem('projectId', data.id);
+						this.$store.dispatch('app/changeUser', user);
+						this.$store.dispatch('app/changeMenuData', user.resource ? JSON.parse(user.resource) : []);
+						setComment(user.menu ? user.menu : JSON.stringify([]));
+						this.$store.dispatch('projectBase/changeProject', data);
+					}
+				});
+			},
+			currentChange(currPage) {
+				this.currPage = currPage;
+				this.init();
+			},
+			insertProject() {
+				this.isUpdate = false;
+				this.visible = true;
+			},
+			updateProject(val) {
+				this.detailId = val.id;
+				this.isUpdate = true;
+				this.visible = true;
+			},
+			lookProject(val) {
+				this.detailId = val.id;
+				this.drawer = true;
+			},
+			deleteProject(val) {
+				if (this.$store.getters.project.id === val.id) return this.$message.warning('不能删除当前项目,请切换项目后删除');
+				this.$confirm('确定要删除该项目?', () => {
+					deleteProjectById(val.id).then(res => {
+						if (res.state) {
+							this.init();
+							this.$message.success('操作成功');
+						}
+					})
+				});
+			},
+			callback(type) {
+				if (type === 'init') this.init();
+				this.visible = false;
+			}
+		},
+		components: {
+			edit,
+			detail
+		},
+	}
+</script>
+
+<style lang="scss"></style>

+ 451 - 0
virgo.wzfrontend/console/src/views/work/space/set/list.vue

@@ -0,0 +1,451 @@
+<template>
+	<div class="space-index">
+		<div class="space-null" v-if="list.length ==0">
+			<img :src="nullImage" alt="" />
+			<div class="space-null-text">您还未添加楼宇信息,可新增楼宇,开启您的空间设置吧!</div>
+			<div class="flow-button">
+				<el-button size="medium" type="primary" @click="insert('projectItem')">
+					<i class="iconfont huifont-xinzeng"></i>新增楼宇
+				</el-button>
+			</div>
+		</div>
+		<div class="space-content">
+			<div class="space-content-item">
+				<div class="space-title">
+					<div class="space-title-label">楼宇</div>
+					<el-button size="medium" type="primary" @click="insert('projectItem')">
+						<i class="iconfont huifont-xinzeng"></i>新增
+					</el-button>
+				</div>
+				<div class="space-content-box">
+					<div class="space-project-item" v-for="(item,index) in list" :key="item.id">
+						<div class="project-item-title">
+							<div class="project-item--label">{{item.name}}</div>
+							<el-dropdown trigger="click" @command="command=>commandFunc(command,item,'projectItem')">
+								<div class="target-item-icon">
+									<i class="iconfont huifont-jinhangzhong"></i>
+								</div>
+								<el-dropdown-menu slot="dropdown">
+									<el-dropdown-item command="update">编辑</el-dropdown-item>
+									<el-dropdown-item command="delete">删除</el-dropdown-item>
+								</el-dropdown-menu>
+							</el-dropdown>
+						</div>
+						<el-row class="project-item-traget" :gutter="10">
+							<el-col :span="8" v-for="(target,index) in item.projectItemTargetList" :key="target.id">
+								<div :class="targetData.id === target.id?'target-item active' : 'target-item'"
+									@click="selectTarget(item,target)">
+									<div class="target-item-num">{{target.elevation}}</div>
+									<div class="target-item-label">{{target.name}}</div>
+									<el-dropdown trigger="click"
+										@command="command=>commandFunc(command,target,'projectItemTarget')">
+										<div class="target-item-icon">
+											<i class="iconfont huifont-jinhangzhong"></i>
+										</div>
+										<el-dropdown-menu slot="dropdown">
+											<el-dropdown-item command="update">编辑</el-dropdown-item>
+											<el-dropdown-item command="delete">删除</el-dropdown-item>
+										</el-dropdown-menu>
+									</el-dropdown>
+								</div>
+							</el-col>
+							<el-col :span="8">
+								<div class="target-item-insert" @click="insert('projectItemTarget',item.id)">
+									<i class="iconfont huifont-xinzeng"></i>新增
+								</div>
+							</el-col>
+						</el-row>
+					</div>
+				</div>
+			</div>
+			<div class="space-line"></div>
+			<div class="space-content-item">
+				<div class="space-title">
+					<div class="space-title-label">{{projectItem.name}} / {{targetData.name}}</div>
+					<el-button size="medium" type="primary" @click="insert('room')">
+						<i class="iconfont huifont-xinzeng"></i>新增
+					</el-button>
+				</div>
+				<div class="space-content-box">
+					<div class="space-undefined" v-if="roomList.length === 0">
+						<img :src="undefinedImage" alt="" />
+						<div class="space-undefined-text">暂无数据</div>
+					</div>
+					<div class="space-room-list">
+						<el-row :gutter="10">
+							<el-col :span="12" v-for="item in roomList" :key="roomList.id">
+								<div class="space-room-item">
+									<div class="space-room-num">{{targetData.elevation}}</div>
+									<div class="space-room-text">
+										<div class="space-room-label">{{item.name}}</div>
+										<div class="space-room-sub">{{item.remark}}</div>
+									</div>
+									<div class="space-room-icon">
+										<el-dropdown trigger="click"
+											@command="command=>commandFunc(command,item,'room')">
+											<div class="target-item-icon">
+												<i class="iconfont huifont-jinhangzhong"></i>
+											</div>
+											<el-dropdown-menu slot="dropdown">
+												<el-dropdown-item command="update">编辑</el-dropdown-item>
+												<el-dropdown-item command="delete">删除</el-dropdown-item>
+											</el-dropdown-menu>
+										</el-dropdown>
+									</div>
+								</div>
+							</el-col>
+						</el-row>
+					</div>
+				</div>
+			</div>
+		</div>
+		<el-dialog :title="isUpdate?'编辑':'新增'" :visible.sync="visible" width="900px" :append-to-body="true">
+			<project-item-form v-if="visible && type === 'projectItem'" @callback="callback" :isUpdate="isUpdate"
+				:detailId="itemId"></project-item-form>
+			<project-item-target-form v-if="visible && type === 'projectItemTarget'" @callback="callback"
+				:isUpdate="isUpdate" :detailId="itemId" :projectItemId="projectItemId"></project-item-target-form>
+			<room-form v-if="visible && type === 'room'" @callback="callback" :isUpdate="isUpdate" :roomId="itemId"
+				:projectItemId="projectItem.id" :targetId="targetData.id">
+			</room-form>
+		</el-dialog>
+	</div>
+</template>
+
+<script>
+	import {
+		getProjectTreeList,
+		deleteProjectItemById,
+		deleteProjectItemTarget,
+		deleteRoom
+	} from '@/httpApi/work';
+	import projectItemForm from '@/components/work/space/set/projectItemForm'
+	// import projectItemTargetForm from '@/components/work/project/projectItemTargetForm'
+	// import roomForm from '@/components/work/space/roomForm'
+	export default {
+		data() {
+			return {
+				nullImage: require('../../../../assets/image/common/dataNull.png'),
+				undefinedImage: require('../../../../assets/image/common/dataUndefined.png'),
+				list: [],
+				roomList: [],
+				visible: false,
+				itemId: '',
+				projectItemId: '',
+				isUpdate: false,
+				targetData: {},
+				projectItem: {}
+			}
+		},
+		created() {
+			this.getProjectItemList();
+		},
+		methods: {
+			getProjectItemList() {
+				getProjectTreeList(this.$store.getters.project.id).then(res => {
+					if (res.state) {
+						this.list = res.data.projectItemList || [];
+						if (this.targetData.id) {
+							let item = this.list.filter(node => node.id === this.projectItem.id);
+							if (item.length > 0) {
+								let traget = item[0].projectItemTargetList.filter(node => node.id === this
+									.targetData.id);
+								if (traget.length > 0) {
+									this.selectTarget(item[0], traget[0]);
+									return;
+								}
+							}
+						}
+						let data = this.list.filter(node => node.projectItemTargetList && node
+							.projectItemTargetList.length > 0);
+						if (data.length > 0) this.selectTarget(data[0], data[0].projectItemTargetList[0]);
+					}
+				})
+			},
+			insert(type, projectItemId) {
+				this.type = type;
+				this.isUpdate = false;
+				this.visible = true;
+				if (projectItemId) this.projectItemId = projectItemId;
+			},
+			selectTarget(item, target) {
+				this.targetData = target;
+				this.projectItem = item;
+				this.roomList = target.projectItemTargetRoomList;
+			},
+			commandFunc(operationType, item, type) {
+				this.type = type;
+				this.itemId = item.id;
+				this[operationType]();
+			},
+			update() {
+				this.isUpdate = true;
+				this.visible = true;
+			},
+			delete() {
+				if (this.type === 'projectItem') {
+					this.$confirm('确定要删除该楼宇?', () => {
+						deleteProjectItemById(this.itemId).then(this.successFunc);
+					});
+				}
+				if (this.type === 'projectItemTarget') {
+					this.$confirm('确定要删除该楼层?', () => {
+						deleteProjectItemTarget(this.itemId).then(this.successFunc);
+					});
+				}
+				if (this.type === 'room') {
+					this.$confirm('确定要删除该房间?', () => {
+						deleteRoom(this.itemId).then(this.successFunc);
+					});
+				}
+			},
+			successFunc(res) {
+				if (res.state) {
+					this.getProjectItemList();
+					this.$message.success('操作成功');
+				}
+			},
+			callback(type) {
+				this.visible = false;
+				if (type === 'init') this.getProjectItemList();
+			}
+		},
+		components: {
+			projectItemForm,
+			// projectItemTargetForm,
+			// roomForm
+		},
+	}
+</script>
+
+<style lang="scss">
+	.space-index {
+		width: 100%;
+		height: 100%;
+
+		.space-null {
+			width: 100%;
+			height: 100%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+
+			img {
+				width: 420px;
+			}
+
+			.space-null-text {
+				padding: 30px 0 20px 0;
+			}
+
+			.el-button {
+				padding-left: 12px;
+
+				span {
+					display: flex;
+					align-items: center;
+				}
+
+				.huifont-xinzeng {
+					padding-right: 10px;
+				}
+			}
+		}
+
+		.space-undefined {
+			width: 100%;
+			height: 100%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+
+			img {
+				width: 160px;
+			}
+
+			.space-undefined-text {
+				margin-top: 20px;
+				opacity: 0.6;
+			}
+		}
+
+		.space-content {
+			width: 100%;
+			height: 100%;
+			display: flex;
+
+			.space-title {
+				display: flex;
+				justify-content: space-between;
+				padding: 15px 20px;
+				align-items: center;
+
+				.space-title-label {
+					font-size: 16px;
+				}
+
+				.el-button {
+					padding: 8px 16px;
+				}
+			}
+
+			.space-line {
+				background: $--background;
+				width: 12px;
+				height: 100%;
+			}
+
+			.space-content-box {
+				flex: 1;
+				padding: 0 20px 15px 20px;
+				height: 0;
+				overflow-y: auto;
+
+				.space-project-item {
+					background: #242a36;
+					margin-bottom: 20px;
+					border-radius: 2px;
+				}
+			}
+
+			.space-content-item {
+				flex: 1;
+				display: flex;
+				flex-direction: column;
+			}
+
+			.project-item-title {
+				height: 56px;
+				display: flex;
+				justify-content: space-between;
+				padding: 0 20px;
+				align-items: center;
+				border-bottom: 1px solid $--color-border;
+			}
+
+			.project-item-traget {
+				padding: 15px 20px;
+
+				.target-item {
+					width: 100%;
+					background: #1f242f;
+					padding: 15px;
+					border-radius: 8px;
+					display: flex;
+					align-items: center;
+					box-sizing: border-box;
+					cursor: pointer;
+					box-sizing: border-box;
+					border: 1px solid #1f242f;
+				}
+
+				.target-item-insert {
+					width: 100%;
+					height: 70px;
+					border: 1px dashed $--color-border;
+					border-radius: 8px;
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					cursor: pointer;
+
+					.huifont-xinzeng {
+						margin-right: 5px;
+					}
+				}
+
+				.target-item-insert:hover {
+					border-color: $--color-primary;
+					color: $--color-primary;
+
+					.huifont-xinzeng {
+						color: $--color-primary;
+					}
+				}
+
+				.target-item.active,
+				.target-item:hover {
+					border-color: $--color-primary;
+					box-shadow: -1px -1px 10px 1px rgba(51, 133, 255, 0.2) inset;
+				}
+
+				.target-item-num {
+					width: 38px;
+					height: 38px;
+					text-align: center;
+					line-height: 38px;
+					background: #31353f;
+					border-radius: 10px;
+					margin-right: 10px;
+				}
+
+				.target-item-label {
+					flex: 1;
+					width: 0;
+					overflow: hidden;
+				}
+			}
+
+			.target-item-icon {
+				transform: rotate(90deg);
+				cursor: pointer;
+
+				.huifont-jinhangzhong {
+					font-size: 20px;
+					color: $--color-common;
+				}
+			}
+
+			.el-col {
+				padding-top: 5px;
+				padding-bottom: 5px;
+			}
+
+			.space-room-list {
+				.space-room-item {
+					display: flex;
+					align-items: center;
+					padding: 0 20px;
+					height: 110px;
+					background: #232A37;
+					border-radius: 8px;
+					position: relative;
+
+					.space-room-icon {
+						position: absolute;
+						top: 12px;
+						right: 12px;
+					}
+
+					.space-room-num {
+						width: 48px;
+						height: 48px;
+						background: rgba(255, 255, 255, 0.08);
+						border-radius: 10px;
+						margin-right: 12px;
+						text-align: center;
+						line-height: 48px;
+						font-size: 18px;
+					}
+
+					.space-room-text {
+						flex: 1;
+						width: 0;
+
+						.space-room-label {
+							font-size: 18px;
+							font-weight: 500;
+							margin-bottom: 4px;
+						}
+
+						.space-room-sub {
+							font-size: 12px;
+							opacity: 0.6;
+						}
+					}
+				}
+			}
+		}
+	}
+</style>

+ 1 - 1
virgo.wzfrontend/console/vue.config.js

@@ -1,4 +1,4 @@
-const dev_baseURL = 'http://git.workark.com:9100';
+const dev_baseURL = 'http://git.waywish.com:9100';
 // const dev_baseURL = 'https://www.workark.com';
 const isProduction = process.env.NODE_ENV === 'production'; //是否为生产环境
 const path = require("path");