123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556 |
- <template>
- <div class="sand-flow-container">
- <div class="left-wrapper" v-if="!isView">
- <tool-bar :graph="graph"/>
- </div>
- <div class="right-wrapper">
- <header class="sand-top">
- <ul class="form-ul">
- <li style="margin-right:30px;">
- 沙盘名称:
- <el-input
- v-model="sandObj.name"
- placeholder="请输入沙盘名称"
- clearable
- style="width:300px">
- </el-input>
- </li>
- <li v-permission="permissionBtn.sandboxPermission.sandbox_variety">
- 品种:
- <el-cascader
- :options="classifyArr"
- :props="classifyProps"
- v-model="sandObj.classify"
- clearable
- placeholder="选择品种"
- size="medium"
- @change="changeClassify"
- />
- </li>
- </ul>
- <div>
- <el-button v-permission="permissionBtn.sandboxPermission.sandbox_saveView"
- type="primary" size="medium" @click="saveChart(null)" v-if="!isView">保存</el-button>
- <el-button v-permission="permissionBtn.sandboxPermission.sandbox_addMy"
- type="primary" size="medium" @click="copySandHandle">复制图片</el-button>
- </div>
- </header>
- <div class="flow-wrapper">
- <div id="flow-container"></div>
- <div class="flow-source">来源:弘则研究</div>
- <!-- 右键菜单 -->
- <div class="contextMenu-wrapper" id="contextMenu-wrapper" @mouseleave="hideContextMenu">
- <el-dropdown-menu size="medium">
- <el-dropdown-item v-for="menu in contextMenuOption" :key="menu.key" @click.native="handleContext(menu.key)">
- <i :class="menu.icon" v-if="menu.icon"/>
- {{menu.label}}
- </el-dropdown-item>
- </el-dropdown-menu>
- </div>
- <!-- 提示区 -->
- <div class="tip-wrapper" v-if="isShowTip">
- <i class="el-icon-d-arrow-left" style="font-size: 60px;"></i>拖拽图形开始绘制
- </div>
- <!-- 缩略图 -->
- <div id="minimap" class="minimap"></div>
- </div>
- </div>
- </div>
- </template>
- <script>
- import { ElDropdownMenu } from 'element-ui';
- import { sandInterface,customInterence,dataBaseInterface } from '@/api/api.js';
- import { myGraph } from '../common/gragh';
- import toolBar from './toolBar';
- import { contextMenuOption } from '../common/options';
- import { contextEvent } from '../common/events';
- import { copyBlob,svgToBase64 } from '@/utils/svgToblob'
- export default {
- name:'',
- components: { toolBar,ElDropdownMenu },
- data () {
- return {
- graph: null,
- sand_id: this.$route.query.id || '',
- contextMenuOption,
- sandObj: {
- name: '',
- classify: ''
- },
- editable_id: '',
- classifyArr:[],
- classifyProps: {
- children: 'Items',
- label: 'ClassifyName',
- value: 'ChartPermissionId'
- },
- initData: {},
- sandInfo:{},
- loopTimer: null,
- lockLoding: null,
- isShowTip: this.$route.query.id ? false : true,
- };
- },
- watch: {
- initData(newval) {
- console.log(newval)
- this.graph.fromJSON(newval);
- },
- },
- computed: {
- isView() {
- return this.$route.query.type === 'view';
- }
- },
- methods: {
- /* 获取品种 */
- getClassify() {
- customInterence.getvariety({
- CompanyType: 'ficc'
- }).then(res => {
- if(res.Ret !== 200) return
- this.classifyArr = res.Data.List;
- })
- },
- /* 获取画布内容 */
- getGraphData(SandboxVersionCode,modifyType) {
- const { id,type } = this.$route.query;
- const sandbox_versioncode = id||SandboxVersionCode
- const modify_type = type||modifyType
- // type === 'edit' && sandInterface.sandData({
- // SandboxId: id
- // }).then(res => {
- // if(res.Ret !== 200) return
- // const { Name,ChartPermissionId,Content } = res.Data;
- // this.sandObj = {
- // name: Name,
- // classify: ChartPermissionId
- // }
- // this.initData = JSON.parse(Content);
- // this.sandInfo = res.Data;
- // // 轮询
- // this.$route.query.type === 'edit' && this.autoSave();
- // })
- if(!sandbox_versioncode) return
- sandInterface.versionData({
- SandboxVersionCode: id||SandboxVersionCode
- }).then(res => {
- if(res.Ret !== 200) return
- const { Name,ChartPermissionId,Content } = res.Data;
- this.sandObj = {
- name: Name,
- classify: ChartPermissionId
- }
- this.initData = JSON.parse(Content);
- this.$nextTick(()=>{
- this.graph.centerContent()
- })
- if(modify_type === 'edit') {
- this.sandInfo = res.Data;
- // 轮询
- this.autoSave();
- //this.graph.centerContent();
- }
- })
- },
- /* 保存 */
- saveChart: _.debounce( function(callback=null) {
- if(!this.sandObj.name)
- return this.$message.warning(`'请填写沙盘名称`);
- if(!this.graph.toJSON().cells.length) return this.$message.warning('请绘制画布内容');
- const { name, classify } = this.sandObj;
- this.lockLoding = this.$loading({
- lock: true,
- text: '保存中...',
- target: '.right-wrapper',
- spinner: 'el-icon-loading',
- background: 'rgba(255, 255, 255, 0.8)'
- });
- const { cells } = this.graph.toJSON();
- this.graph.toSVG(async (dataUri) => {
- const params = new FormData();
- params.append('Img',dataUri)
- const { Data } = await dataBaseInterface.uploadImgSvg(params);
- //let SandboxVersionCode = (this.sand_id && classify === this.sandInfo.ChartPermissionId) ? this.sand_id : '';
- let SandboxVersionCode = this.sand_id
- const { Ret , Data : sandData} = await sandInterface.sandSave({
- SandboxVersionCode,
- Name: name,
- ChartPermissionId: Number(classify),
- Content: JSON.stringify(this.graph.toJSON()),
- PicUrl: Data.ResourceUrl,
- SvgData: dataUri
- })
- if(Ret !== 200) return;
- this.$message.success(`${SandboxVersionCode ? '编辑成功' : '保存成功'}`);
- this.lockLoding.close();
- //!SandboxVersionCode && window.close();
- //如果是新增,直接跳转到编辑页面
- if(!SandboxVersionCode&&sandData.VersionCode){
- this.sand_id = sandData.VersionCode
- this.$router.push({
- path: '/sandflow',
- query: {
- id: sandData.VersionCode,
- type:'edit',
- },
- });
- this.getGraphData(sandData.VersionCode,'edit');
- return
- }
-
- callback && callback();
- },{
- preserveDimensions:true,//让svg为实际图片大小
- beforeSerialize:(svg)=>{
- const {x,y,width,height} = this.graph.getContentBBox(cells)
- let {tx,ty} = this.graph.translate() // 画布偏移量
- //给导出的svg增加一点宽高
- svg.setAttribute('width',width+50)
- svg.setAttribute('height',height+50)
- //设置viewBox使图像居中
- svg.setAttribute('viewBox',`${x-25} ${y-25} ${width+50} ${height+50}`)
- // 在图表右下方 加上"来源:弘则研究"字样
- let gNode = svg.getElementsByClassName('x6-graph-svg-viewport')[0]
- let textNode = document.createElement('text')
- textNode.setAttribute('x',x-tx+width-90)
- textNode.setAttribute('y',y-ty+height+22)
- textNode.setAttribute('font-size','16px')
- textNode.setAttribute('font-style','italic')
- textNode.innerText = '来源:弘则研究'
- gNode.appendChild(textNode)
- },
- copyStyles:false,
- stylesheet: `
- svg{
- background-color:white;
- }
- .x6-port {
- visibility: hidden;
- }
- `
- })
-
- },500),
- /* 复制图片 */
- copySandHandle: _.debounce(function() {
- const { cells } = this.graph.toJSON();
- if(!cells.length) return this.$message.warning('当前画布无可复制内容');
- this.lockLoding = this.$loading({
- lock: true,
- text: '复制图片中...',
- target: '.right-wrapper',
- spinner: 'el-icon-loading',
- background: 'rgba(255, 255, 255, 0.8)'
- });
- this.graph.toSVG(async(dataUri) => {
- /* const params = new FormData();
- params.append('Img',dataUri)
- const { Data } = await dataBaseInterface.uploadImgSvg(params);
- const copyImg = document.createElement('img');
- $('.sand-flow-container')[0].appendChild(copyImg);
- copyImg.src = Data.ResourceUrl;
- this.getSelect(copyImg);
- setTimeout(() => {
- document.execCommand('copy');
- $('.sand-flow-container')[0].removeChild(copyImg);
- this.lockLoding && this.lockLoding.close();
- this.$message.success('复制成功');
- }); */
- const canvas = document.createElement("canvas");
- const ctx = canvas.getContext("2d");
- const img = new Image();
- img.crossOrigin = "Anonymous";
- img.src = svgToBase64(dataUri);
- img.onload = ()=>{
- canvas.width = img.width;
- canvas.height = img.height;
- console.log('width',img.width)
- console.log('height',img.height)
- ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
- ctx.fillStyle="#fff";
- ctx.fillRect(0, 0, img.width, img.height);
- ctx.drawImage(img, 0, 0);
- if(window.ClipboardItem) {
- canvas.toBlob(async (blob) => {
- const data = [new ClipboardItem({ [blob.type]: blob })];
- await navigator.clipboard.write(data).then(
- () => {
- this.$message.success('复制成功!')
- },
- () => {
- this.$message.warning('复制失败,稍后再试')
- }
- ).finally(()=>{
- this.lockLoding && this.lockLoding.close();
- });
- });
- }else {
- this.lockLoding && this.lockLoding.close();
- this.$message.warning('当前协议暂不支持,仅支持https协议')
- }
- }
- },{
- preserveDimensions:true,//让svg为实际图片大小
- beforeSerialize:(svg)=>{
- const {x,y,width,height} = this.graph.getContentBBox(cells)
- let {tx,ty} = this.graph.translate()
- //给导出的svg增加一点宽高
- svg.setAttribute('width',width+50)
- svg.setAttribute('height',height+50)
- //设置viewBox使图像居中
- svg.setAttribute('viewBox',`${x-25} ${y-25} ${width+50} ${height+50}`)
- let gNode = svg.getElementsByClassName('x6-graph-svg-viewport')[0]
- let textNode = document.createElement('text')
- textNode.setAttribute('x',x-tx+width-90)
- textNode.setAttribute('y',y-ty+height+22)
- textNode.setAttribute('font-size','16px')
- textNode.setAttribute('font-style','italic')
- textNode.innerText = '来源:弘则研究'
- gNode.appendChild(textNode)
- },
- copyStyles:false,
- stylesheet: `
- svg{
- background-color:white;
- }
- .x6-port {
- visibility: hidden;
- }`
-
- })
- },500),
-
- /* 右键事件 */
- handleContext(key) {
- contextEvent(this.graph, key);
- this.hideContextMenu();
- },
- /* 隐藏右键menu */
- hideContextMenu() {
- const dom = $('#contextMenu-wrapper')[0];
- dom.style.left = '-9999px';
- dom.style.top = '-9999px';
- },
- // 选择
- getSelect(targetNode) {
- if (window.getSelection) {
- //chrome等主流浏览器
- var selection = window.getSelection();
- var range = document.createRange();
- range.selectNode(targetNode);
- selection.removeAllRanges();
- selection.addRange(range);
- } else if (document.body.createTextRange) {
- //ie
- var range = document.body.createTextRange();
- range.moveToElementText(targetNode);
- range.select();
- }
- },
- changeClassify(e) {
- this.sandObj.classify = e.length ? e[1] : '';
- },
- /* 编辑页 自动保存 */
- autoSave() {
- this.loopTimer = setInterval(() => {
- if(!this.sandObj.name || !this.sandObj.classify) return;
- const { name, classify } = this.sandObj;
- sandInterface.draftSave({
- SandboxVersionCode: this.sand_id,
- Name: name,
- ChartPermissionId: classify,
- Content: JSON.stringify(this.graph.toJSON())
- }).then((res) => {
- if(res.Ret === 202) return clearInterval(this.loopTimer);
- // if (res.Ret !== 200) return;
- });
- }, 10000);
- },
- /* init画布 */
- init() {
- const graph = new myGraph('flow-container');
- //graph.centerContent();
- // graph.fromJSON(this.initData);
- this.graph = graph;
- }
- },
-
- beforeRouteLeave(to,from,next) {
- // 编辑页 添加页切换路由提示保存
- if(this.$route.query.type !== 'view') {
- this.$confirm("在离开页面之前,是否保存当前内容?", "保存提示", {
- type: "warning"
- }).then(() => {
- this.saveChart(() => {
- this.$route.query.type === 'edit' && sandInterface.mark({ SandboxId:this.sandInfo.SandboxId,Status:2 });
- next();
- });
- }).catch(() => {
- this.$route.query.type === 'edit' && sandInterface.mark({ SandboxId:this.sandInfo.SandboxId,Status:2 });
- this.$route.query.type === 'edit' && sandInterface.cancelSave({ SandboxId:this.sandInfo.SandboxId });
- next();
- })
- }else {
- next();
- }
- },
- mounted() {
- this.init();
- this.getClassify();
- this.$route.query.id && this.getGraphData();
-
- },
- destroyed() {
- if(this.loopTimer) clearInterval(this.loopTimer);
- }
- }
- </script>
- <style lang='scss'>
- .sand-flow-container {
- display: flex;
- height: calc(100vh - 120px);
- * { box-sizing: border-box;}
- .left-wrapper {
- width: 300px;
- min-width: 300px;
- height: 100%;
- margin-right: 20px;
- background-color: #fff;
- border: 1px solid #ececec;
- box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
- }
- .right-wrapper {
- flex: 1;
- height: 100%;
- border: 1px solid #ececec;
- position: relative;
- overflow: hidden;
- .sand-top {
- padding: 10px 20px;
- background: #fff;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- display: flex;
- border-bottom: 1px solid #ECECEC;
- z-index: 1;
- .form-ul {
- flex: 1;
- display: flex;
- }
- }
- .flow-wrapper {
- position: relative;
- height: 100%;
- display: flex;
- /* overflow: auto; */
- padding-top: 60px;
- // padding-bottom:30px;
- .flow-source{
- position: absolute;
- right: 10px;
- bottom: 8px;
- font-size: 20px;
- font-family: PingFang SC-Regular, PingFang SC;
- font-weight: 400;
- color: #666666;
- }
- #flow-container {
- flex: 1;
- }
- .x6-graph-scroller {
- flex: 1;
- }
- .x6-port-body {
- display: none;
- }
- /* reseize 框样式 */
- .x6-widget-transform {
- .x6-widget-transform-resize {
- border-radius: 0;
- }
- }
-
- .contextMenu-wrapper {
- position: fixed;
- z-index: 99;
- top: -9999px;
- left: -9999px;
- background: #fff;
- padding: 10px 0;
- /* border: 1px solid #999; */
- box-shadow: 0 1px 4px #999;
- }
- .editable-wrapper {
- position: fixed;
- top: -999px;
- left: -999px;
- outline: none;
- z-index: 99;
- padding: 5px;
- }
- .tip-wrapper {
- position: absolute;
- top: 50%;
- left: 10%;
- z-index: 99;
- font-size: 40px;
- color: #bbb;
- display: flex;
- align-items: center;
- }
- .minimap{
- position:absolute;
- right:6px;
- bottom:6px;
- box-sizing: border-box;
- .x6-widget-minimap-viewport{
- border-color: red;
- .x6-widget-minimap-viewport-zoom{
- border-color: red;
- }
- }
- .x6-widget-minimap{
- width: auto !important;
- height: auto !important;
- }
- }
- }
- }
- }
- </style>
|