whx hai 1 ano
pai
achega
73f83d2001
Modificáronse 76 ficheiros con 1435 adicións e 78 borrados
  1. 5 0
      virgo.wzfrontend/console/package-lock.json
  2. 1 0
      virgo.wzfrontend/console/package.json
  3. 132 0
      virgo.wzfrontend/console/src/components/common/house/treeDetail.vue
  4. 8 1
      virgo.wzfrontend/console/src/components/common/projectItemTreeSelect.vue
  5. 23 4
      virgo.wzfrontend/console/src/components/common/listFilter.vue
  6. 433 0
      virgo.wzfrontend/console/src/components/document/editor.vue
  7. 148 0
      virgo.wzfrontend/console/src/components/work/contract/common/clauseDetail.vue
  8. 40 25
      virgo.wzfrontend/console/src/components/work/contract/common/selectTemplate.vue
  9. 364 0
      virgo.wzfrontend/console/src/components/work/contract/list/detail.vue
  10. 51 5
      virgo.wzfrontend/console/src/components/work/contract/list/edit.vue
  11. 67 0
      virgo.wzfrontend/console/src/httpApi/contract.js
  12. 23 0
      virgo.wzfrontend/console/src/httpApi/organization.js
  13. 1 0
      virgo.wzfrontend/console/src/store/getters.js
  14. 9 0
      virgo.wzfrontend/console/src/store/modules/app.js
  15. 36 1
      virgo.wzfrontend/console/src/uitls/index.js
  16. 6 0
      virgo.wzfrontend/console/src/views/system/log.vue
  17. 34 10
      virgo.wzfrontend/console/src/views/work/contract/list.vue
  18. 1 1
      virgo.wzfrontend/src/main/resources/static/index.html
  19. 1 0
      virgo.wzfrontend/src/main/resources/static/static/css/197.15cb5418.css
  20. 0 1
      virgo.wzfrontend/src/main/resources/static/static/css/337.34ca17c0.css
  21. 0 1
      virgo.wzfrontend/src/main/resources/static/static/css/346.34ca17c0.css
  22. 0 0
      virgo.wzfrontend/src/main/resources/static/static/css/527.52c2cdde.css
  23. 1 1
      virgo.wzfrontend/src/main/resources/static/static/css/110.20e33a6e.css
  24. 1 0
      virgo.wzfrontend/src/main/resources/static/static/css/924.15cb5418.css
  25. 0 0
      virgo.wzfrontend/src/main/resources/static/static/css/972.f43f4c00.css
  26. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/102-legacy.09864e3e.js
  27. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/153-legacy.f60fe8b9.js
  28. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/17-legacy.3c1572db.js
  29. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/17-legacy.877d5901.js
  30. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/197-legacy.853f0344.js
  31. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/202.5b7814d2.js
  32. 11 0
      virgo.wzfrontend/src/main/resources/static/static/js/263.e6ac192c.js
  33. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/293.a99d398c.js
  34. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/293.adf2df45.js
  35. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/337-legacy.f75ba3ba.js
  36. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/346.8ba9dd49.js
  37. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/39.6ad7ff94.js
  38. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/449.7f22257b.js
  39. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/498-legacy.2517fa46.js
  40. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/498-legacy.61762d88.js
  41. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/510.e9849c2f.js
  42. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/525-legacy.8449865f.js
  43. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/529-legacy.32bbec41.js
  44. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/529-legacy.b417da01.js
  45. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/529.a938767d.js
  46. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/197-legacy.c676dcc9.js
  47. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/6.6207fce6.js
  48. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/609.0ba8181f.js
  49. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/61-legacy.20a0bb66.js
  50. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/61-legacy.fcfc9dbc.js
  51. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/61.20a0bb66.js
  52. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/61.fcfc9dbc.js
  53. 0 0
      virgo.wzfrontend/src/main/resources/static/static/js/636-legacy.6c99893f.js
  54. 0 0
      virgo.wzfrontend/src/main/resources/static/static/js/64.4351bf83.js
  55. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/654-legacy.c0da7fba.js
  56. 0 0
      virgo.wzfrontend/src/main/resources/static/static/js/656-legacy.b63345d8.js
  57. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/689.55bbcf85.js
  58. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/740.bceb3564.js
  59. 0 0
      virgo.wzfrontend/src/main/resources/static/static/js/836-legacy.a695668c.js
  60. 0 0
      virgo.wzfrontend/src/main/resources/static/static/js/836.54fa45a6.js
  61. 1 1
      virgo.wzfrontend/src/main/resources/static/static/js/838-legacy.2e598b02.js
  62. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/842.6b6de035.js
  63. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/842.d08f2115.js
  64. 11 0
      virgo.wzfrontend/src/main/resources/static/static/js/867-legacy.64ea79f3.js
  65. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/896-legacy.6896544f.js
  66. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/896-legacy.6e4aafc7.js
  67. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/896.813e1da1.js
  68. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/896.fca04400.js
  69. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/919-legacy.671c405d.js
  70. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/919-legacy.aad17af2.js
  71. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/924.1aca7843.js
  72. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/972.a2ae0f64.js
  73. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/app-legacy.4901e24c.js
  74. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/app-legacy.86f09e92.js
  75. 1 0
      virgo.wzfrontend/src/main/resources/static/static/js/app.874ee3de.js
  76. 0 1
      virgo.wzfrontend/src/main/resources/static/static/js/app.e01852aa.js

+ 5 - 0
virgo.wzfrontend/console/package-lock.json

@@ -8720,6 +8720,11 @@
 				"@sideway/pinpoint": "^2.0.0"
 			}
 		},
+		"jquery": {
+			"version": "3.7.1",
+			"resolved": "https://registry.npmmirror.com/jquery/-/jquery-3.7.1.tgz",
+			"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
+		},
 		"js-base64": {
 			"version": "2.6.4",
 			"resolved": "https://registry.npmmirror.com/js-base64/-/js-base64-2.6.4.tgz",

+ 1 - 0
virgo.wzfrontend/console/package.json

@@ -12,6 +12,7 @@
 		"core-js": "^3.3.2",
 		"dayjs": "^1.11.11",
 		"element-ui": "^2.15.13",
+		"jquery": "^3.7.1",
 		"path-browserify": "^1.0.1",
 		"svg-sprite-loader": "^6.0.11",
 		"terser-webpack-plugin": "^3.0.1",

+ 132 - 0
virgo.wzfrontend/console/src/components/common/house/treeDetail.vue

@@ -0,0 +1,132 @@
+<template>
+	<div class="project-item-tree-select">
+		<el-collapse v-model="active">
+			<el-collapse-item :name="index" v-for="(item,index) in options" :key="item.id">
+				<template slot="title">
+					<i class="iconfont huifont-shuzhuangcaidantubiao"></i>
+					<span class="el-collapse-name">{{item.name}}</span>
+				</template>
+				<div>
+					<el-tree :ref="'houseTree' + item.id" :data="item.children" :props="defaultProps"
+						default-expand-all>
+					</el-tree>
+				</div>
+			</el-collapse-item>
+		</el-collapse>
+	</div>
+</template>
+
+<script>
+	import {
+		getHouseTree,
+	} from '@/httpApi/space'
+	import {
+		roomCheckedList
+	} from '@/uitls'
+	export default {
+		props: ['ids'],
+		data() {
+			return {
+				options: [],
+				defaultProps: {
+					children: 'children',
+					label: 'optionName'
+				},
+				idsBox: [],
+				active: []
+			}
+		},
+		created() {
+			this.idsBox = this.ids.split(',');
+			this.init();
+		},
+		methods: {
+			init() {
+				getHouseTree(this.$store.getters.project.id).then(res => {
+					if (res.state) {
+						this.options = roomCheckedList(res.data.projectItemList || [], this.idsBox);
+						for (var i = 0; i < this.options.length; i++) {
+							this.active.push(i)
+						}
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.project-item-tree-select {
+		flex: 1;
+		height: 0;
+		overflow-y: auto;
+
+		.el-tree {
+			.el-tree-node__label {
+				left: 5px;
+			}
+		}
+
+		.el-collapse {
+			border: none;
+
+			.el-collapse-item__header {
+				background: #1E2430;
+				color: $--color-common !important;
+				border-color: $--color-border;
+				height: 32px;
+				line-height: 32px;
+				font-size: 12px;
+				padding: 0 14px;
+
+				.el-collapse-name {
+					flex: 1;
+					width: 0;
+					overflow: hidden;
+				}
+
+				.iconfont {
+					color: $--color-common !important;
+					margin-right: 6px;
+				}
+
+				.huifont-bumen {
+					font-size: 16px;
+				}
+
+				.huifont-shuzhuangcaidantubiao,
+				.huifont-moxingguanli {
+					font-size: 18px;
+				}
+			}
+
+			.el-collapse-item__wrap {
+				background: #151c26;
+				border: none;
+			}
+
+			.el-collapse-item__header.is-active,
+			.el-collapse-item__header:hover,
+			.el-collapse-item__header:focus {
+				color: $--color-common;
+				background: #262C38;
+			}
+
+			.el-icon-arrow-right {
+				font-family: 'iconfont' !important;
+				font-size: 9px;
+				margin: 0;
+			}
+
+			.el-icon-arrow-right::before {
+				content: '\e738';
+			}
+
+			.el-collapse-item__content {
+				padding-bottom: 0;
+				color: $--color-common;
+				font-size: 12px;
+			}
+		}
+	}
+</style>

+ 8 - 1
virgo.wzfrontend/console/src/components/common/projectItemTreeSelect.vue

@@ -49,7 +49,6 @@
 						this.options = roomList(res.data.projectItemList || []);
 						if (this.ids) {
 							this.idsBox = this.ids.split(',');
-							console.log(this.idsBox);
 							this.returnChecked(this.options);
 						}
 					}
@@ -64,6 +63,14 @@
 				}
 				return data;
 			},
+			returnHouseItem() {
+				let data = [];
+				for (let i = 0; i < this.options.length; i++) {
+					data = data.concat(this.$refs['houseTree' + this.options[i].id][0].getCheckedNodes(true).filter(node =>
+						node.roomId));
+				}
+				return data;
+			},
 			returnChecked(data) {
 				for (let i = 0; i < data.length; i++) {
 					if (data[i]['roomId']) {

+ 23 - 4
virgo.wzfrontend/console/src/components/common/listFilter.vue

@@ -2,7 +2,7 @@
 	<div class="hui-content-filter">
 		<div class="filter-box" v-if="type === 'customer'">
 			<div class="filter-item">
-				<el-input v-model="customer.name" placeholder="请输入客户名称"></el-input>
+				<el-input prefix-icon="el-icon-search" v-model="customer.name" placeholder="请输入客户名称"></el-input>
 			</div>
 			<div class="filter-item">
 				<el-select v-model="customer.type" placeholder="请选择客户类型">
@@ -21,7 +21,7 @@
 		</div>
 		<div class="filter-box" v-if="type === 'highseas'">
 			<div class="filter-item">
-				<el-input v-model="highseas.name" placeholder="请输入客户名称"></el-input>
+				<el-input prefix-icon="el-icon-search" v-model="highseas.name" placeholder="请输入客户名称"></el-input>
 			</div>
 			<div class="filter-item">
 				<el-select v-model="highseas.type" placeholder="请选择客户类型">
@@ -33,7 +33,20 @@
 		</div>
 		<div class="filter-box" v-if="type === 'agent'">
 			<div class="filter-item">
-				<el-input v-model="agent.name" placeholder="请输入客户名称"></el-input>
+				<el-input prefix-icon="el-icon-search" v-model="agent.name" placeholder="请输入客户名称"></el-input>
+			</div>
+		</div>
+		<div class="filter-box" v-if="type === 'contract'">
+			<div class="filter-item">
+				<el-input prefix-icon="el-icon-search" v-model="contract.code" placeholder="请输入合同编号"></el-input>
+			</div>
+			<div class="filter-item">
+				<el-date-picker v-model="contract.startDate" value-format="yyyy-MM-dd" type="date" placeholder="请选择开始日">
+				</el-date-picker>
+			</div>
+			<div class="filter-item">
+				<el-date-picker v-model="contract.endDate" value-format="yyyy-MM-dd" type="date" placeholder="请选择结束日">
+				</el-date-picker>
 			</div>
 		</div>
 		<div class="filter-btn">
@@ -62,7 +75,13 @@
 				agent: {
 					name: ''
 				},
-				agentData: {}
+				agentData: {},
+				contract: {
+					code: '',
+					startDate: '',
+					endDate: ''
+				},
+				contractData: {},
 			}
 		},
 		created() {

+ 433 - 0
virgo.wzfrontend/console/src/components/document/editor.vue

@@ -0,0 +1,433 @@
+<template>
+	<div class="flow-document hui-flex">
+		<div class="hui-flex-box">
+			<div id="html" class="html" ref="html" v-html="html" @click="selectClick"></div>
+		</div>
+		<div class="hui-dialog-submit">
+			<el-button size="medium" type="primary" @click="submit">保 存</el-button>
+			<el-button size="medium" @click="$emit('close')">取 消</el-button>
+		</div>
+		<el-dialog title="选择日期" :visible.sync="timeDialog" :append-to-body="true" width="500px">
+			<div class="hui-flex">
+				<div class="hui-flex-box">
+					<date ref="dateTime"></date>
+				</div>
+				<div class="hui-dialog-submit">
+					<el-button size="medium" type="primary" @click="selectSuccess('time')">确 定</el-button>
+					<el-button size="medium" @click="timeDialog = false">取 消</el-button>
+				</div>
+			</div>
+		</el-dialog>
+		<el-dialog title="选择内容" :visible.sync="selectVisible" width="30%" :append-to-body="true">
+			<div class="hui-flex">
+				<div class="hui-flex-box">
+					<el-radio-group v-model="selectVal">
+						<div class="select-item" v-for="(value, name, index) in selectItem" :key="index">
+							<el-radio :label="value">{{ value }}</el-radio>
+						</div>
+					</el-radio-group>
+				</div>
+				<div class="hui-dialog-submit">
+					<el-button size="medium" @click="selectVisible = false">取 消</el-button>
+					<el-button size="medium" type="primary" @click="selectSuccess('select')">确 定</el-button>
+				</div>
+			</div>
+		</el-dialog>
+		<el-dialog title="选择公章" :visible.sync="dialogVisibles" width="880px" :append-to-body="true">
+			<div class="no-tips" v-if="sealData.length == 0">暂未添加公章</div>
+			<el-radio v-else v-model="sealVal" v-for="item in sealData" :key="item.id" :label="item.id" border
+				style="margin: 10px;">{{ item.name }}</el-radio>
+			<div class="dialog-footer">
+				<el-button @click="dialogVisibles = false">取 消</el-button>
+				<el-button type="primary" @click="selectSeal">确 定</el-button>
+			</div>
+		</el-dialog>
+		<!-- <verify-qr ref="verifyQr"></verify-qr> -->
+		<el-upload ref="upload" :action="action" name="uploadFile" style="position: absolute;z-index: -1;opacity: 0;"
+			:headers="headers" :on-success="successFile" :show-file-list="false">
+			<el-button slot="trigger" size="small" type="primary" ref="imgUpload">上传文件</el-button>
+		</el-upload>
+	</div>
+</template>
+
+<script>
+	import {
+		getDocumentById,
+		getDocumentTemplateById,
+		createDocument,
+		insertDocumentData,
+		getSealRegisterKey,
+		getRetrievers,
+	} from '@/httpApi/contract';
+	import {
+		getSealList,
+		requestSeal,
+		getSealDetailById,
+		getRequestSealDetail
+	} from '@/httpApi/organization';
+	import $ from 'jquery';
+	import {
+		constData
+	} from '@/uitls/index.js';
+	// import verifyQr from '@/components/verifyQr';
+	import {
+		getUserInfo
+	} from '@/httpApi/loginRegister';
+	export default {
+		props: ['documentId', 'templateId'],
+		data() {
+			return {
+				html: '', //html
+				changeSelect: [], //选择项
+				timeDialog: false, //选择日期是否显示
+				nowElem: '', //选择时点击的节点
+				selectVisible: false, //选择内容是否显示
+				selectVal: '', //选中的内容
+				selectItem: {}, //选择的数据
+				selectData: {}, //有极选项总数据
+				contextData: {}, //有极拉取数据
+				userInfo: {}, //登录人信息
+				submitShow: false, //是否显示保存按钮
+				hasData: false, //是否为编辑文档
+				sealData: [], //印章数据
+				sealDomId: '', //印章存放节点的id
+				dialogVisibles: false, //是否选择印章
+				sealVal: 1, //当前选择的印章
+				initIndex: 1, //初始化文档
+				organized: {
+					executionRecordList: 10, //施工方意见
+					supervisionRecordList: 4, //监理单位意见
+					constructionRecordList: 3, //建设单位意见
+					designRecordList: 2, //设计单位意见
+					prospectedRecordList: 5, //勘察单位意见
+					governmentRecordList: 6, //政府单位
+					supervisorRecordList: 4 //监理(建设)单位验收记录(监理单位验收记录,表中)
+				},
+				platformType: '1',
+				action: '',
+				headers: {
+					token: ''
+				},
+				copyImage: {}
+			};
+		},
+		created() {
+			this.$nextTick(() => {
+				this.userInfo = this.$store.getters.user;
+				this.contextData = this.$store.getters.document;
+				console.log(this.contextData);
+				if (this.templateId) return this.initTemplate(this.templateId, [], []);
+				if (this.documentId) this.initDocument();
+			})
+		},
+		methods: {
+			initTemplate(templateId, elementData, sealData) {
+				getDocumentTemplateById(templateId).then(res => {
+					if (res.state) {
+						this.html = res.data.html;
+						this.templateName = res.data.name;
+						this.renderTamplate(elementData, sealData);
+					}
+				})
+			},
+			initDocument() {
+				getDocumentById(this.documentId).then(res => {
+					if (res.state) {
+						this.initTemplate(res.data.documentTemplateId, res.data.elementDataList, res.data
+							.sealUsageList);
+						this.documentSealRegister(res.data.id);
+					}
+				})
+			},
+			successFile(data, file, type) {
+				//上传头像成功
+				let _self = this;
+				if (data.state) {
+					_self.copyImage.dom.innerHTML = '<img id="' + _self.copyImage.domId +
+						'" class="copy-img copyImage" src="' + data
+						.data.node.url + '"/>'
+				}
+			},
+			documentSealRegister(documentId) {
+				getSealRegisterKey(documentId).then(res => {
+					if (res.state) {
+						res.data.forEach(item => {
+							$('#' + item.keyWord).css('position', 'relative');
+							$('#' + item.keyWord).html(
+								'<img id="' +
+								item.keyWord +
+								'" class="seal-img" src="' +
+								(item.fileNode.node.url ||
+									'https://file-node.oss-cn-shanghai.aliyuncs.com/youji/8b726641d0cc45fe91b5e59e4ea450c6'
+								) +
+								'"/>'
+							);
+						});
+					}
+				});
+			},
+			renderTamplate(elementDataList, sealUsageList) {
+				//整合模板
+				this.$nextTick(() => {
+					if (elementDataList.length === 0) {
+						let documentElement = $('.documentElement');
+						for (let i = 0; i < documentElement.length; i++) {
+							let elem = documentElement[i];
+							let inputtype = $(elem).attr('inputtype') == undefined ? '' : $(elem).attr(
+								'inputtype');
+							this.domRender(inputtype, elem, elem.id);
+						}
+					} else {
+						this.renderDocument(elementDataList);
+					}
+				});
+			},
+			domRender(type, elem, id) {
+				elem.innerHTML = '';
+				switch (type) {
+					case 'context':
+						$(elem).text(this.contextData[id] || '')
+						break;
+					case 'sign':
+						elem.innerHTML =
+							'<button class="sureAutograph el-button el-button--default el-button--medium">确认签名</button>';
+						break;
+					case 'seal':
+						elem.innerHTML = '<div class="sureSeal"">申请印章</div>';
+						break;
+					default:
+						break;
+				}
+			},
+			renderDocument(data) {
+				data.forEach(item => {
+					let dataItem = JSON.parse(item.data);
+					console.log(dataItem);
+					for (let i in dataItem) {
+						for (let j in dataItem[i]) {
+							console.log(i, j, dataItem[i][j]);
+							this.renderDom(i, j, dataItem[i][j]);
+						}
+					}
+				});
+			},
+			renderDom(i, j, text) {
+				switch (i) {
+					case 'seal':
+						if (text == '') return;
+						$('#' + j)[0].className = '';
+						$('#' + j).html('已申请印章,请等待审核');
+						break;
+					case 'sealperson':
+						break;
+					case 'sign':
+						$('#' + j + '[inputtype=' + i + ']').html('<img class="autograph" src="' + text + '">');
+						break;
+					case 'signQR':
+						$('#' + j + '[inputtype=' + i + ']').html('<img class="autograph" src="' + text + '">');
+						break;
+					case 'copyImage':
+						$('#' + j + '[inputtype=' + i + ']').html('<img  class="copy-img" src="' + text + '"/>');
+						break;
+					default:
+						if (i.indexOf('.') == -1) {
+							$('#' + j + '[inputtype=' + i + ']').text(text);
+						}
+						break;
+				}
+			},
+			updateRenderDom(i, j, text) {
+				let _self = this,
+					oldI = i;
+				i = i.indexOf('select_') > -1 ? i.split('_')[0] : i;
+				switch (i) {
+					case 'input':
+						$('#' + j + '[name="' + i + '"]')
+							.attr('contenteditable', true)
+							.attr('class', 'documentElement inputElement')
+							.html(text);
+						_self.submitShow = true;
+						break;
+					case 'select':
+						if ($('#' + j + '[name="' + oldI + '"]').hasClass('documentElement')) {
+							$('#' + j + '[name="' + oldI + '"]').text(text);
+							break;
+						}
+						let keys = oldI.split('.')[0].split('_')[1],
+							html = '<div class="documentElement" id="' + j + '" name="' + oldI +
+							'" contenteditable="true">' + text + '</div>';
+						$('#' + j + '[name="' + oldI + '"]')
+							.attr('id', '')
+							.attr('class', 'selectElement')
+							.html(html + '<i id="' + keys + '" class="el-icon-arrow-down"></i>');
+						_self.changeSelect.push(keys);
+						_self.submitShow = true;
+						break;
+					case 'context':
+						$('#' + j + '[name="' + i + '"]')
+							.attr('contenteditable', true)
+							.attr('class', 'documentElement contextElement')
+							.html(text);
+						break;
+					case 'seal':
+						$('#' + j)[0].className = '';
+						$('#' + j).html('已申请印章,请等待审核');
+						break;
+					case 'sealperson':
+						if (text != '') $('#' + j).html('<img class="autograph" src="' + text + '">');
+						break;
+					case 'sign':
+						if (text != '') $('#' + j).html('<img class="autograph" src="' + text + '">');
+						break;
+					case 'signQR':
+						if (text != '') $('#' + j).html('<img class="autograph" src="' + text + '">');
+						break;
+					case 'dateTime':
+						if ($('#' + j + '[name="' + oldI + '"]').hasClass('documentElement')) {
+							$('#' + j + '[name="' + oldI + '"]').text(text);
+							break;
+						}
+						let timehtml = '<div class="documentElement" id="' + j + '" name="' + oldI +
+							'"contenteditable="true">' + text + '</div>';
+						$('#' + j + '[name="' + oldI + '"]')
+							.attr('id', '')
+							.attr('class', 'dateTimeElement')
+							.html(timehtml + '<i class="el-icon-date"></i>');
+						_self.submitShow = true;
+						break;
+					case 'checkbox':
+						$('#' + j + '[name="' + i + '"]')
+							.attr('class', 'documentElement checkboxElement')
+							.html(text);
+						_self.submitShow = true;
+						break;
+					case 'copyImage':
+						if (text != '') {
+							$('#' + j)[0].className = 'documentElement copyImageElement';
+							$('#' + j).html('<img class="copyImage" src="' + text + '">');
+						}
+						_self.submitShow = true;
+						break;
+					default:
+						$('#' + j + '[name="' + i + '"]').html(text);
+						break;
+				}
+			},
+			filterSeal(data) {
+				//渲染印章
+				let _self = this;
+				if (_self.platformType == '1') return;
+				data.forEach((item, index) => {
+					getRequestSealDetail(item.requestId).then(node => {
+						if (node.code == '200') {
+							let data = node.data;
+							if (data.status == 1) {
+								$('#' + data.keyWord).css('position',
+									'relative');
+								getSealDetailById(data.sealId).then(item => {
+									if (item.code == '200') $('#' + data
+										.keyWord).html('<img id="' + data
+										.keyWord + '" class="seal-img" src="' +
+										item.data.fileNode.node.url + '"/>');
+								})
+							}
+						}
+					})
+				});
+			},
+			selectClick(event) {
+				let _self = this;
+				_self.nowElem = event.target; //当前点击的i标签
+				switch (event.target.className) {
+					case 'el-icon-arrow-down':
+						_self.selectItem = _self.selectData[_self.nowElem.id];
+						_self.selectVal = '';
+						_self.selectVisible = true;
+						break;
+					case 'el-icon-date':
+						_self.timeDialog = true;
+						break;
+					default:
+						break;
+				}
+			},
+			selectSuccess(type) {
+				let _self = this;
+				switch (type) {
+					case 'time':
+						_self.nowElem.parentNode.getElementsByClassName('documentElement')[0].innerHTML = _self.$refs
+							.dateTime.getDate();
+						_self.timeDialog = false;
+						break;
+					case 'select':
+						_self.nowElem.parentNode.getElementsByClassName('documentElement')[0].innerHTML = _self.selectVal;
+						_self.selectVisible = false;
+						break;
+					default:
+						break;
+				}
+			},
+			selectSeal() {
+				//选择印章
+				let _self = this;
+				if (_self.sealDomId == '') return;
+				_self.$refs.verifyQr.createVerifyQr('seal', null, function() {
+					let item = _self.sealData.filter(item => {
+						return item.id == _self.sealVal;
+					})[0];
+					requestSeal({
+						sealId: item.id,
+						requestUserName: _self.userInfo.name,
+						requestUserId: _self.userInfo.userId,
+						documentId: _self.documentId,
+						keyWord: _self.sealDomId,
+						projectId: _self.$store.getters.project.id
+					}).then(data => {
+						if (data.state) {
+							$('#' + _self.sealDomId).css('position', 'relative');
+							$('#' + _self.sealDomId).html('<img id="' + _self.sealDomId +
+								'" class="seal-img" src="' + item.fileNode.node.url + '"/>');
+							_self.dialogVisibles = false;
+						}
+					});
+				});
+			},
+			submit() {
+				let documentElement = $('.documentElement');
+				let obj = constData(documentElement);
+				if (this.documentId) this.updateDocument(obj);
+			},
+			updateDocument(obj) {
+				insertDocumentData({
+					data: JSON.stringify(obj),
+					documentId: this.documentId,
+					userId: this.$store.getters.user.userId
+				}).then(res => {
+					if (res.state) {
+						this.$message.success('保存成功');
+						this.$emit('close');
+					}
+				})
+			}
+		},
+		components: {}
+	};
+</script>
+
+<style lang="scss">
+	.flow-document {
+		position: relative;
+		width: 100%;
+		height: 100%;
+		overflow: auto;
+
+		&::-webkit-scrollbar-thumb {
+			background: #D9DEE6;
+		}
+
+		.html {
+			margin: 0 auto;
+			width: 900px;
+		}
+	}
+</style>

+ 148 - 0
virgo.wzfrontend/console/src/components/work/contract/common/clauseDetail.vue

@@ -0,0 +1,148 @@
+<template>
+	<div class="clause-detail-box">
+		<div class="clause-box-form" v-if="type === 1">
+			<div class="contract-form-item">
+				<div class="name">计租方式</div>
+				<div class="label">{{$field.findTypeName('rentWay', detail.rentWay)}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">开始时间</div>
+				<div class="label">{{detail.startTime}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">结束时间</div>
+				<div class="label">{{detail.endTime}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">合同单价(元/月)</div>
+				<div class="label">{{detail.unitPrice}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">付款时间</div>
+				<div class="label">{{$field.findTypeName('payTime', detail.payTime)}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">计费类型</div>
+				<div class="label">{{$field.findTypeName('chargingType', detail.chargingType)}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">非自然月计费方式</div>
+				<div class="label">
+					{{$field.findTypeName('unnaturalMonthChargingWay', detail.unnaturalMonthChargingWay)}}
+				</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">年天数</div>
+				<div class="label">{{detail.yearDays}}天</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">付款周期(几月一付)</div>
+				<div class="label">{{detail.payCycle}}月</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">租期划分方式</div>
+				<div class="label">{{$field.findTypeName('unnaturalMonthChargingWay', detail.leaseTermWay)}}</div>
+			</div>
+		</div>
+		<div class="clause-box-form" v-if="type === 2">
+			<div class="contract-form-item">
+				<div class="name">保证金类型</div>
+				<div class="label">{{$field.findTypeName('earnestMoneyType', detail.earnestMoneyType)}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">保证金金额</div>
+				<div class="label">{{detail.earnestMoney}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">币种</div>
+				<div class="label">{{$field.findTypeName('currencyType', detail.currencyType)}}</div>
+			</div>
+		</div>
+		<div class="clause-box-form" v-if="type === 3">
+			<div class="contract-form-item">
+				<div class="name">递增时间点</div>
+				<div class="label">{{detail.incrementalTime}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">单价递增</div>
+				<div class="label">{{detail.incrementalUnitPrice}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">保证金递增</div>
+				<div class="label">{{detail.incrementalEarnestMoney}}</div>
+			</div>
+		</div>
+		<div class="clause-box-form" v-if="type === 4">
+			<div class="contract-form-item">
+				<div class="name">优惠类型</div>
+				<div class="label">{{$field.findTypeName('preferentialType', detail.preferentialType)}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">开始时间</div>
+				<div class="label">{{detail.preferentialStartTime}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">结束时间</div>
+				<div class="label">{{detail.preferentialEndTime}}</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">免租期划分方式</div>
+				<div class="label">
+					{{$field.findTypeName('preferentialRentFreeWay', detail.preferentialRentFreeWay)}}
+				</div>
+			</div>
+			<div class="contract-form-item">
+				<div class="name">备注</div>
+				<div class="label">{{detail.preferentialRemark}}</div>
+			</div>
+		</div>
+	</div>
+</template>
+
+<script>
+	export default {
+		props: ['type', 'detail'],
+		data() {
+			return {}
+		},
+		created() {},
+		methods: {},
+	}
+</script>
+
+<style lang="scss">
+	.clause-detail-box {
+		width: 100%;
+		position: relative;
+		padding-top: 20px;
+
+		&::before {
+			background: $--background;
+			content: '';
+			height: 12px;
+			top: -10px;
+			right: 0;
+			left: -25px;
+			position: absolute;
+		}
+
+		.clause-box-form {
+			width: 100%;
+			padding-right: 10px;
+			display: flex;
+			flex-wrap: wrap;
+		}
+
+		.contract-form-item {
+			width: 16.6666%;
+			padding-right: 15px;
+			margin-bottom: 15px;
+		}
+
+		.name {
+			font-size: 12px;
+			opacity: 0.8;
+			margin-bottom: 5px;
+		}
+	}
+</style>

+ 40 - 25
virgo.wzfrontend/console/src/components/work/contract/common/selectTemplate.vue

@@ -1,7 +1,7 @@
 <template>
 	<div class="hui-flex select-template">
 		<div class="select-template-content">
-			<div class="hui-content-insert">
+			<div class="hui-content-insert" v-if="type === 'insert'">
 				<el-button type="primary" size="medium" @click="selectTemplate">
 					选择合同模板
 				</el-button>
@@ -17,10 +17,10 @@
 					<el-table-column label="操作" width="240">
 						<template slot-scope="scope">
 							<div class="hui-table-operation">
-								<span class="table-operation" @click="preview(scope.row)">
-									预览
+								<span class="table-operation" v-if="type === 'insert'">
+									编辑
 								</span>
-								<span class="table-operation" @click="deleteItem(scope.row)">
+								<span class="table-operation" v-if="type === 'insert'" @click="deleteItem(scope.row)">
 									删除
 								</span>
 							</div>
@@ -33,8 +33,8 @@
 			</div>
 		</div>
 		<div class="line-select-template"></div>
-		<div class="select-template-content">
-			<div class="hui-content-insert">
+		<div class="select-template-content" style="margin-bottom: 0;">
+			<div class="hui-content-insert" v-if="type === 'insert'">
 				<el-button type="primary" size="medium" @click="uploadFile">
 					上传合同附件
 				</el-button>
@@ -51,7 +51,7 @@
 					<el-table-column label="操作" width="240">
 						<template slot-scope="scope">
 							<div class="hui-table-operation">
-								<span class="table-operation" @click="deleteFile(scope.row)">
+								<span class="table-operation" v-if="type === 'insert'" @click="deleteFile(scope.row)">
 									删除
 								</span>
 							</div>
@@ -63,10 +63,10 @@
 				</el-table>
 			</div>
 		</div>
-		<el-dialog title="预览" :visible.sync="detailsDialogVisible" width="80%" class="document-dialog"
+		<el-dialog :title="file.name" :visible.sync="documentShow" class="document-dialog" width="80%"
 			:append-to-body="true">
-			<preview v-if="detailsDialogVisible" :templateId="templateId" @close="detailsDialogVisible = false">
-			</preview>
+			<editor :documentId="file.id" v-if="documentShow" @close="documentShow = false" @submit="submit">
+			</editor>
 		</el-dialog>
 		<el-dialog title="选择合同模板" custom-class="select-template-dialog" :visible.sync="visible" width="500px"
 			:append-to-body="true">
@@ -98,17 +98,20 @@
 
 <script>
 	import preview from '@/components/document/preview'
+	import editor from '@/components/document/editor'
 	import uploadFile from '@/components/common/uploadFile'
 	import {
 		getContractTemplateList,
-		getTagList
+		getTagList,
+		createDocument
 	} from '@/httpApi/contract'
 	export default {
-		props: ['documentFileList'],
+		props: ['documentFileList', 'type'],
 		data() {
 			return {
 				templateData: [],
-				detailsDialogVisible: false,
+				documentShow: false,
+				file: {},
 				templateId: '',
 				visible: false,
 				tableData: [],
@@ -156,8 +159,8 @@
 				});
 			},
 			preview(item) {
-				this.templateId = item.id;
-				this.detailsDialogVisible = true;
+				this.file = item;
+				this.documentShow = true;
 			},
 			change() {
 				this.form.templateId = '';
@@ -185,16 +188,27 @@
 				this.fileList.push(data);
 			},
 			submit() {
-				if (this.templateData.filter(node => node.id == this.form.templateId).length > 0) return this.$message
-					.warning('该模板已存在');
 				let data = this.templateList.filter(node => node.id == this.form.templateId)[0];
-				if (!data) return;
-				this.templateData.push(data);
-				this.visible = false;
-				this.form = {
-					selectValue: [],
-					templateId: ''
-				}
+				if (!data) return this.$message.warning('请选择文档模板');
+				createDocument({
+					documentTemplateId: data.id,
+					name: data.name
+				}).then(res => {
+					if (res.state) {
+						this.templateData.push({
+							id: res.data.id,
+							name: res.data.name
+						});
+						this.visible = false;
+						this.form = {
+							selectValue: [],
+							templateId: ''
+						}
+					}
+				});
+
+
+
 			},
 			returnData() {
 				return {
@@ -211,7 +225,8 @@
 		},
 		components: {
 			preview,
-			uploadFile
+			uploadFile,
+			editor
 		},
 	}
 </script>

+ 364 - 0
virgo.wzfrontend/console/src/components/work/contract/list/detail.vue

@@ -0,0 +1,364 @@
+<template>
+	<div class="hui-flex contract-detail">
+		<div class="contract-step">
+			<div :class="stepId === item.id ?'step-item active':'step-item'" v-for="(item,index) in stepList"
+				@click="stepId = item.id">
+				<div class="step-number">
+					<i :class="item.icon"></i>
+				</div>
+				<div class="step-label">{{item.name}}</div>
+			</div>
+		</div>
+		<div class="hui-flex-box" v-show="stepId === 1">
+			<div class="contract-left">
+				<div class="contract-box">
+					<div class="hui-chart-title">所属公司信息</div>
+					<div class="contract-from">
+						<div class="contract-from-item">
+							<div class="name">所属公司</div>
+							<div class="label">{{organization.name}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">所属部门</div>
+							<div class="label">{{detail.roleName}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">招商跟进人</div>
+							<div class="label">{{detail.investmentPromotionName}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">运营跟进人</div>
+							<div class="label">{{detail.operatorName}}</div>
+						</div>
+					</div>
+				</div>
+				<div class="contract-box">
+					<div class="hui-chart-title">租客信息</div>
+					<div class="contract-from">
+						<div class="contract-from-item">
+							<div class="name">运营跟进人</div>
+							<div class="label">{{detail.tenantType == 1?'企业':'客户'}}</div>
+						</div>
+						<div class="contract-from-item" v-if="detail.tenantType === 1">
+							<div class="name">企业</div>
+							<div class="label">{{detail.merchantName}}</div>
+						</div>
+						<div class="contract-from-item" v-else-if="detail.tenantType === 2">
+							<div class="name">客户</div>
+							<div class="label">{{detail.clientName}}</div>
+						</div>
+						<div class="contract-from-item" v-if="detail.tenantType === 1">
+							<div class="name">法人</div>
+							<div class="label">{{detail.corporation}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">行业</div>
+							<div class="label">{{detail.industry}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">签订人</div>
+							<div class="label">{{detail.signatory}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">租客联系人</div>
+							<div class="label">{{detail.tenantContactPerson}}</div>
+						</div>
+					</div>
+				</div>
+				<div class="contract-box">
+					<div class="hui-chart-title">基本信息</div>
+					<div class="contract-from">
+						<div class="contract-from-item">
+							<div class="name">签订日</div>
+							<div class="label">{{detail.signingDate}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">开始日</div>
+							<div class="label">{{detail.startDate}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">结束日</div>
+							<div class="label">{{detail.endDate}}</div>
+						</div>
+					</div>
+				</div>
+				<div class="contract-box">
+					<div class="hui-chart-title">滞纳金</div>
+					<div class="contract-from">
+						<div class="contract-from-item">
+							<div class="name">起算天数(天)</div>
+							<div class="label">{{detail.lateFeesStartingDays}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">滞纳金比例(%/天)</div>
+							<div class="label">{{detail.lateFeesProportion}}</div>
+						</div>
+						<div class="contract-from-item">
+							<div class="name">滞纳金上限(%)</div>
+							<div class="label">{{detail.lateFeesCeiling}}</div>
+						</div>
+					</div>
+				</div>
+				<div class="contract-box">
+					<div class="hui-chart-title">合同标签</div>
+					<div class="contract-from" style="padding-bottom: 20px;">
+						<tag ref="tag" type="look" :tagType="4"
+							:tagActive="detail.tagIds ? detail.tagIds.split(',') : []">
+						</tag>
+					</div>
+				</div>
+				<div class="contract-box" v-if="detail.data && detail.data != '[]'">
+					<div class="hui-chart-title">自定义字段</div>
+					<div class="contract-from">
+						<div class="contract-from-item" v-for="(item,index) in JSON.parse(detail.data)" :key="index">
+							<div class="name">{{item.keyName}}</div>
+							<div class="label">{{item.value}}</div>
+						</div>
+						<div class="hui-detail-item">
+							<div class="hui-detail-label"></div>
+							<div class="hui-detail-value"></div>
+						</div>
+					</div>
+				</div>
+			</div>
+			<div class="contract-right">
+				<div class="contract-project-list">
+					<div class="contract-project-title">
+						<svg-icon name="zhuangshi" width="16" height="20"></svg-icon>
+						<span class="hui-left-tree-sub">签约房源</span>
+					</div>
+					<tree-detail :ids="detail.projectItemTargetRoomIds || ''" v-if="detail.id"></tree-detail>
+				</div>
+			</div>
+		</div>
+		<div class="hui-flex-box" v-show="stepId === 2">
+			<div class="contract-clause">
+				<div class="contract-box" v-for="(clause,index) in clauseData" :key="clause.id">
+					<div class="hui-chart-title">
+						<span>{{clause.name}}</span>
+					</div>
+					<div class="contract-from">
+						<clause-detail :type="item.type" v-for="(item,index) in clause.children" :key="item.id"
+							:detail="item">
+						</clause-detail>
+					</div>
+				</div>
+			</div>
+		</div>
+		<div class="hui-flex-box" v-show="stepId === 3">
+			<select-template type="look" :documentFileList="documentFileList"></select-template>
+		</div>
+	</div>
+</template>
+
+<script>
+	import {
+		getContractDetailById
+	} from '@/httpApi/contract'
+	import tag from '@/components/common/tag'
+	import clauseDetail from '@/components/work/contract/common/clauseDetail'
+	import treeDetail from '@/components/common/house/treeDetail'
+	import selectTemplate from '@/components/work/contract/common/selectTemplate'
+	export default {
+		props: ['detailId'],
+		data() {
+			return {
+				stepList: [{
+					id: 1,
+					name: '基本信息',
+					icon: 'el-icon-tickets'
+				}, {
+					id: 2,
+					name: '费用条款',
+					icon: 'el-icon-document-copy'
+				}, {
+					id: 3,
+					name: '合同文本',
+					icon: 'el-icon-takeaway-box'
+				}],
+				stepId: 1,
+				detail: {
+					clauseList: []
+				},
+				organization: {},
+				clauseList: [{
+					id: 1,
+					name: '租期条款'
+				}, {
+					id: 2,
+					name: '保证金条款'
+				}, {
+					id: 3,
+					name: '递增条款'
+				}, {
+					id: 4,
+					name: '优惠条款'
+				}],
+				clauseData: [],
+				documentFileList: {
+					document: [],
+					attachment: []
+				},
+			}
+		},
+		created() {
+			this.organization = this.$store.getters.organization;
+			this.init();
+		},
+		methods: {
+			init() {
+				getContractDetailById(this.detailId).then(res => {
+					if (res.state) {
+						this.detail = res.data;
+						this.clauseData = this.clauseList.map(clause => {
+							clause['children'] = this.detail.clauseList.filter(node => node.type === clause
+								.id);
+							return clause;
+						}).filter(node => node.children.length > 0);
+						this.documentFileList = {
+							document: this.detail.document ? JSON.parse(this.detail.document) : [],
+							attachment: this.detail.attachment ? JSON.parse(this.detail.attachment) : []
+						}
+					}
+				})
+			}
+		},
+		components: {
+			tag,
+			clauseDetail,
+			treeDetail,
+			selectTemplate
+		},
+	}
+</script>
+
+<style lang="scss">
+	.contract-detail {
+		.hui-flex-box {
+			background: $--background;
+			display: flex;
+			padding: 12px 0;
+		}
+
+		.contract-clause {
+			flex: 1;
+			width: 0;
+			height: 100%;
+			overflow-y: auto;
+		}
+
+		.contract-left {
+			flex: 2;
+			width: 0;
+			height: 100%;
+			overflow-y: auto;
+			padding-right: 5px;
+		}
+
+		.contract-right {
+			flex: 1;
+			width: 0;
+			height: 100%;
+			padding-left: 5px;
+
+			.contract-project-list {
+				background: $--box-background;
+				height: 100%;
+				display: flex;
+				flex-direction: column;
+			}
+
+			.contract-project-title {
+				height: 42px;
+				border-radius: 2px;
+				display: flex;
+				align-items: center;
+				padding: 0 12px;
+				border-bottom: 1px solid $--color-border;
+			}
+
+		}
+
+		.contract-box {
+			padding: 10px 0 0 10px;
+			background: $--box-background;
+			margin-bottom: 12px;
+
+			.hui-chart-title {
+				padding-right: 20px;
+			}
+
+			.contract-from {
+				padding: 20px 0 0 15px;
+				display: flex;
+				flex-wrap: wrap;
+
+				.contract-from-item {
+					width: 33.333%;
+					padding-right: 15px;
+					margin-bottom: 15px;
+				}
+
+				.name {
+					font-size: 12px;
+					opacity: 0.8;
+					margin-bottom: 5px;
+				}
+			}
+
+			&:last-child {
+				margin-bottom: 0;
+			}
+		}
+
+		.contract-step {
+			display: flex;
+			align-items: center;
+
+			.step-item {
+				display: flex;
+				align-items: center;
+				width: 200px;
+				justify-content: center;
+				height: 50px;
+				cursor: pointer;
+				position: relative;
+			}
+
+			.el-icon-arrow-right {
+				position: absolute;
+				top: 16px;
+				right: -8px;
+				font-size: 18px;
+			}
+
+			.step-number {
+				width: 26px;
+				height: 26px;
+				border-radius: 50%;
+				background: $--color-background;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-right: 15px;
+			}
+
+			.step-item.active {
+				&::before {
+					content: '';
+					position: absolute;
+					bottom: 0;
+					height: 2px;
+					right: 20px;
+					left: 20px;
+					background: $--color-primary;
+				}
+
+				.step-number {
+					background: $--color-primary;
+					color: #fff;
+				}
+			}
+		}
+	}
+</style>

+ 51 - 5
virgo.wzfrontend/console/src/components/work/contract/list/edit.vue

@@ -130,8 +130,8 @@
 						<svg-icon name="zhuangshi" width="16" height="20"></svg-icon>
 						<span class="hui-left-tree-sub">房源列表</span>
 					</div>
-					<project-item-tree-select ref="houseItem" :ids="form.projectItemTargetRoomIds">
-					</project-item-tree-select>
+					<tree-select ref="houseItem" :ids="form.projectItemTargetRoomIds">
+					</tree-select>
 				</div>
 			</div>
 		</el-form>
@@ -154,7 +154,7 @@
 			</div>
 		</div>
 		<div class="hui-flex-box" v-show="stepId === 3">
-			<select-template ref="selectTemplate" :documentFileList="documentFileList"></select-template>
+			<select-template ref="selectTemplate" type="insert" :documentFileList="documentFileList"></select-template>
 		</div>
 		<div class="contract-btn">
 			<el-button size="medium" @click="lastSubmit" v-if="stepId > 1">上一步</el-button>
@@ -167,7 +167,7 @@
 	import {
 		getPartList
 	} from '@/httpApi/organization'
-	import projectItemTreeSelect from '@/components/common/projectItemTreeSelect'
+	import treeSelect from '@/components/common/house/treeSelect'
 	import {
 		getOrganizationList,
 	} from '@/httpApi/business'
@@ -390,6 +390,51 @@
 				if (this.stepId === 1) return this.$emit('callback');
 				this.stepId--;
 			},
+			setDocumentData() {
+				let data = this.form;
+				let signingDate = this.returnDate(data.signingDate),
+					houseItems = this.returnAddress(this.$refs.houseItem.returnHouseItem()),
+					startDate = this.returnDate(data.startDate),
+					endDate = this.returnDate(data.endDate);
+				let obj = {
+					partya: data.organizationName,
+					partyb: data.merchantName,
+					signyear: signingDate.year,
+					signmonth: signingDate.month,
+					signday: signingDate.day,
+					address: houseItems.address,
+					area: houseItems.area,
+					startyear: startDate.year,
+					startmonth: startDate.month,
+					startday: startDate.day,
+					endyear: endDate.year,
+					endmonth: endDate.month,
+					endday: endDate.day,
+					price: this.clauseDataBox[0].unitPrice,
+					deposit: this.clauseDataBox[1].earnestMoney,
+				}
+				this.$store.dispatch('app/changeDocument', obj);
+			},
+			returnDate(date) {
+				let dateStr = date.split('-');
+				return {
+					year: dateStr[0],
+					month: dateStr[1],
+					day: dateStr[2]
+				}
+			},
+			returnAddress(data) {
+				let address = [],
+					area = [];
+				for (let i = 0; i < data.length; i++) {
+					address.push(data[i].projectItemName + '-' + data[i].projectItemTargetName + '-' + data[i].roomNumber);
+					area.push(data[i].area);
+				}
+				return {
+					address: address.join('、'),
+					area: area.join('、'),
+				}
+			},
 			submit() {
 				if (this.stepId === 1) {
 					this.$refs.form.validate((valid) => {
@@ -411,6 +456,7 @@
 					Promise.all(promise).then(res => {
 						this.clauseDataBox = res;
 						this.stepId++;
+						this.setDocumentData();
 					})
 				} else if (this.stepId === 3) {
 					let selectTemplate = this.$refs.selectTemplate.returnData();
@@ -455,7 +501,7 @@
 			}
 		},
 		components: {
-			projectItemTreeSelect,
+			treeSelect,
 			tag,
 			customData,
 			clause,

+ 67 - 0
virgo.wzfrontend/console/src/httpApi/contract.js

@@ -230,4 +230,71 @@ export function deleteContractById(id) {
 		url: `/api/contract/delete/${id}`,
 		method: 'delete'
 	})
+}
+/* 
+ * 新增文档
+ * 
+ * 
+ */
+export function createDocument(data) {
+	return request({
+		url: `/file/document`,
+		method: 'post',
+		data: data
+	})
+}
+/* 
+ * 获取某id文档
+ * 
+ */
+export function getDocumentById(id) {
+	return request({
+		url: `/file/document/${id}`,
+		method: 'get',
+	})
+}
+/* 
+ * 通过id获取模板详情
+ * 
+ * 
+ */
+export function getDocumentTemplateById(id) {
+	return request({
+		url: `/file/template/${id}`,
+		method: 'get'
+	})
+}
+/* 
+ * 保存文档数据
+ * @param {Object} data = {}
+ * 
+ */
+export function insertDocumentData(data) {
+	return request({
+		url: `/file/elementdata/`,
+		method: 'post',
+		data: data
+	})
+}
+/* 
+ * 获取文档下使用的印章
+ * @param {Object} data = {}
+ * 
+ */
+export function getSealRegisterKey(documentId) {
+	return request({
+		url: `/file/sealRegisterkey/${documentId}`,
+		method: 'get',
+	})
+}
+/* 
+ * 获取文档选择参数
+ * @param {Object} data = {}
+ * 
+ */
+export function getRetrievers(retrievers) {
+	return request({
+		url: `/file/document/retrievers/${retrievers}`,
+		method: 'get',
+	})
 }

+ 23 - 0
virgo.wzfrontend/console/src/httpApi/organization.js

@@ -205,4 +205,27 @@ export function getSealRequestListByQuery(data) {
 		url: `/file/sealRequest/${data.sealId}/${data.currPage}/${data.pageSize}`,
 		method: 'get'
 	})
+}
+/* 
+ * 申请使用公章
+ * @param {Object} data = {}
+ * 
+ */
+export function requestSeal(data) {
+	return request({
+		url: `/file/sealRequest`,
+		method: 'post',
+		data: data
+	})
+}
+/*
+ * 申请公章详情
+ * @param {Object} data = {}
+ * 
+ */
+export function getRequestSealDetail(id) {
+	return request({
+		url: `/file/sealRequest/${id}`,
+		method: 'get',
+	})
 }

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

@@ -5,5 +5,6 @@ const getters = {
 	organization: state => state.app.organization, //所属组织信息
 	project: state => state.projectBase.project || {}, //项目
 	config: state => state.app.config, //url配置信息
+	document: state => state.app.document, //模板context渲染
 }
 export default getters

+ 9 - 0
virgo.wzfrontend/console/src/store/modules/app.js

@@ -8,6 +8,7 @@ const state = {
 	organization: {},
 	menuData: [],
 	config: {},
+	document: {}
 }
 
 const mutations = {
@@ -25,6 +26,9 @@ const mutations = {
 	},
 	CHANGE_CONFIG: (state, config) => {
 		state.config = config;
+	},
+	CHANGE_DOCUMENT: (state, document) => {
+		state.document = document;
 	}
 }
 
@@ -53,6 +57,11 @@ const actions = {
 		commit
 	}, config) {
 		commit('CHANGE_CONFIG', config);
+	},
+	changeDocument({
+		commit
+	}, document) {
+		commit('CHANGE_DOCUMENT', document);
 	}
 }
 

+ 36 - 1
virgo.wzfrontend/console/src/uitls/index.js

@@ -387,6 +387,41 @@ export function roomList(data) {
 	})
 	return newArr;
 }
+/**
+ * 返回项目单位工程房间选择的层级关系
+ * @param {array} data 树形结构数据源
+ * @returns {array} 
+ */
+export function roomCheckedList(data, roomIds) {
+	let newArr = JSON.parse(JSON.stringify(data));
+	let index = 1;
+	newArr = newArr.map(item => {
+		item['projectItemId'] = item['id'];
+		item['id'] = index;
+		item['projectItem'] = item;
+		item['optionName'] = item['name'];
+		index++;
+		item['children'] = item.projectItemTargetList.map(target => {
+			target['projectItemTargetId'] = target['id'];
+			target['id'] = index;
+			target['projectItem'] = item;
+			target['optionName'] = target['name'];
+			index++;
+			target['children'] = target.projectItemTargetRoomList.map(room => {
+				room['roomId'] = room['id'];
+				room['id'] = index;
+				room['projectItem'] = item;
+				room['projectItemTarget'] = target;
+				room['optionName'] = room['roomNumber'];
+				index++;
+				return room;
+			}).filter(room => roomIds.filter(node => node == room.roomId).length > 0);
+			return target
+		}).filter(target => target.children.length > 0);
+		return item;
+	}).filter(target => target.children.length > 0);
+	return newArr;
+}
 /**
  * 返回sheet去除data里null数据
  * @param {array} data 结构数据源
@@ -425,7 +460,7 @@ export function constData(documentElement) {
 	for (var i = 0; i < documentElement.length; i++) {
 		let elem = documentElement[i];
 		let id = elem.getAttribute('id'),
-			name = elem.getAttribute('name');
+			name = elem.getAttribute('inputtype');
 		if (!name || name == 'null' || elem.innerText == '申请印章' || elem.innerText == '确认签名' || elem.innerText ==
 			'使用注册章')
 			continue;

+ 6 - 0
virgo.wzfrontend/console/src/views/system/log.vue

@@ -26,6 +26,12 @@
 					<div class="log-item">1、新增获取合同列表、创建合同、编辑合同的功能。</div>
 					<div class="log-item">2、新增合同服务条款的功能。</div>
 				</div>
+			</el-timeline-item>
+			<el-timeline-item timestamp="2024-06-11" placement="top">
+				<div class="log-box">
+					<div class="log-item">1、新增合同详情的功能、合同列表筛选功能。</div>
+					<div class="log-item">2、将合同字段填入文档中。</div>
+				</div>
 			</el-timeline-item>
 		</el-timeline>
 	</div>

+ 34 - 10
virgo.wzfrontend/console/src/views/work/contract/list.vue

@@ -5,6 +5,7 @@
 				<div class="hui-title-item active">合同列表</div>
 			</div>
 			<div class="hui-flex-box hui-flex hui-table">
+				<list-filter type="contract" @filter="filterInit"></list-filter>
 				<div class="hui-content-insert">
 					<el-button type="primary" size="medium" @click="insert">新增合同</el-button>
 				</div>
@@ -21,7 +22,15 @@
 								{{scope.row.tenantType === 1 ? scope.row.merchantName: scope.row.clientName}}
 							</template>
 						</el-table-column>
-						<el-table-column label="房号" prop="projectItemTargetRoomIds"></el-table-column>
+						<el-table-column label="房号" prop="projectItemTargetRoomIds">
+							<template slot-scope="scope">
+								<div class="hui-ellipsis">
+									<span v-for="(item,index) in scope.row.roomMap">
+										{{item}}、
+									</span>
+								</div>
+							</template>
+						</el-table-column>
 						<el-table-column label="开始日" prop="startDate"></el-table-column>
 						<el-table-column label="结束日" prop="endDate"></el-table-column>
 						<el-table-column label="运营跟进人" prop="operatorName"></el-table-column>
@@ -52,17 +61,21 @@
 				</div>
 			</div>
 		</div>
-		<div class="hui-flex" v-else-if="type === 'edit'">
+		<div class="hui-flex" v-else>
 			<div class="hui-nav">
-				<el-page-header @back="type = 'list'" content="新建合同"></el-page-header>
+				<el-page-header @back="type = 'list'" :content="type === 'edit'?'新建合同':'合同详情'"></el-page-header>
 			</div>
-			<edit class="hui-flex-box" @callback="callback" :detailId="detailId"></edit>
+			<edit v-if="type === 'edit'" class="hui-flex-box" @callback="callback" :detailId="detailId"></edit>
+			<detail v-else class="hui-flex-box" @callback="callback" :detailId="detailId"></detail>
 		</div>
 	</div>
 </template>
 
 <script>
 	import edit from '@/components/work/contract/list/edit'
+	import detail from '@/components/work/contract/list/detail'
+	import listFilter from '@/components/common/listFilter'
+
 	import {
 		getContractListByPage,
 		deleteContractById
@@ -75,7 +88,8 @@
 				currPage: 1,
 				pageSize: 10,
 				totalCount: 0,
-				detailId: ''
+				detailId: '',
+				filterOption: {}
 			}
 		},
 		created() {
@@ -83,17 +97,24 @@
 		},
 		methods: {
 			init() {
-				getContractListByPage({
+				let postData = {
 					currPage: this.currPage,
 					pageSize: this.pageSize,
 					organizationId: this.$store.getters.organization.id
-				}).then(res => {
+				}
+				postData = Object.assign(postData, this.filterOption);
+				getContractListByPage(postData).then(res => {
 					if (res.state) {
 						this.tableData = res.data.dataList;
 						this.totalCount = res.data.totalCount;
 					}
 				})
 			},
+			filterInit(option) {
+				this.filterOption = option;
+				this.currPage = 1;
+				this.init();
+			},
 			insert() {
 				this.detailId = '';
 				this.type = 'edit';
@@ -102,8 +123,9 @@
 				this.currPage = currPage;
 				this.init();
 			},
-			detailItem() {
-				this.$message.warning('功能开发中~~~')
+			detailItem(item) {
+				this.detailId = item.id;
+				this.type = 'detail';
 			},
 			updateItem(item) {
 				this.detailId = item.id;
@@ -128,7 +150,9 @@
 			}
 		},
 		components: {
-			edit
+			edit,
+			detail,
+			listFilter
 		},
 	}
 </script>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/index.html


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/css/197.15cb5418.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/css/337.34ca17c0.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/css/346.34ca17c0.css


virgo.wzfrontend/src/main/resources/static/static/css/376.52c2cdde.css → virgo.wzfrontend/src/main/resources/static/static/css/527.52c2cdde.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/css/110.20e33a6e.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/css/924.15cb5418.css


virgo.wzfrontend/src/main/resources/static/static/css/609.f43f4c00.css → virgo.wzfrontend/src/main/resources/static/static/css/972.f43f4c00.css


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/102-legacy.09864e3e.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/153-legacy.f60fe8b9.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/17-legacy.3c1572db.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/17-legacy.877d5901.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/197-legacy.853f0344.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/202.5b7814d2.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 11 - 0
virgo.wzfrontend/src/main/resources/static/static/js/263.e6ac192c.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/293.a99d398c.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/293.adf2df45.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/337-legacy.f75ba3ba.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/346.8ba9dd49.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/39.6ad7ff94.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/449.7f22257b.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/498-legacy.2517fa46.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/498-legacy.61762d88.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/510.e9849c2f.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/525-legacy.8449865f.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/529-legacy.32bbec41.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/529-legacy.b417da01.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/529.a938767d.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/197-legacy.c676dcc9.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/6.6207fce6.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/609.0ba8181f.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/61-legacy.20a0bb66.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/61-legacy.fcfc9dbc.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/61.20a0bb66.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/61.fcfc9dbc.js


virgo.wzfrontend/src/main/resources/static/static/js/636-legacy.36487c56.js → virgo.wzfrontend/src/main/resources/static/static/js/636-legacy.6c99893f.js


virgo.wzfrontend/src/main/resources/static/static/js/64.c6e44433.js → virgo.wzfrontend/src/main/resources/static/static/js/64.4351bf83.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/654-legacy.c0da7fba.js


virgo.wzfrontend/src/main/resources/static/static/js/656-legacy.881cab5a.js → virgo.wzfrontend/src/main/resources/static/static/js/656-legacy.b63345d8.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/689.55bbcf85.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/740.bceb3564.js


virgo.wzfrontend/src/main/resources/static/static/js/836-legacy.80c1c45c.js → virgo.wzfrontend/src/main/resources/static/static/js/836-legacy.a695668c.js


virgo.wzfrontend/src/main/resources/static/static/js/836.25868d7a.js → virgo.wzfrontend/src/main/resources/static/static/js/836.54fa45a6.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
virgo.wzfrontend/src/main/resources/static/static/js/838-legacy.2e598b02.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/842.6b6de035.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/842.d08f2115.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 11 - 0
virgo.wzfrontend/src/main/resources/static/static/js/867-legacy.64ea79f3.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/896-legacy.6896544f.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/896-legacy.6e4aafc7.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/896.813e1da1.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/896.fca04400.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/919-legacy.671c405d.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/919-legacy.aad17af2.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/924.1aca7843.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/972.a2ae0f64.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/app-legacy.4901e24c.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/app-legacy.86f09e92.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 0
virgo.wzfrontend/src/main/resources/static/static/js/app.874ee3de.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 1
virgo.wzfrontend/src/main/resources/static/static/js/app.e01852aa.js