process-setting.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. <template>
  2. <div class="main-div" style="width:100%;height:100%;" ref="mainDiv">
  3. <Layout style="width:100%;height:calc(100% - 68px);">
  4. <Layout style="width:100%;height:100%;">
  5. <!-- 左侧工具栏 -->
  6. <Sider :width="180">
  7. <div id="stencil"></div>
  8. </Sider>
  9. <!-- 中间流程图 -->
  10. <Content>
  11. <div id="container" ref="container" style="width:100%;height:100%"/>
  12. </Content>
  13. <!-- 底部按钮 -->
  14. </Layout>
  15. <Footer class="footer">
  16. <div class="tools">
  17. <Poptip trigger="hover" >
  18. <Button icon="ios-options"></Button>
  19. <div slot="content" style="background: #f8f8f9">
  20. <Card title="快捷键说明" icon="ios-options" :padding="0" shadow style="width: 350px;">
  21. <CellGroup>
  22. <Cell title="复制">
  23. <div slot="extra" style="display: flex">
  24. <div class="key">Ctrl</div>
  25. <div class="key">C</div>
  26. </div>
  27. </Cell>
  28. <Cell title="剪切">
  29. <div slot="extra" style="display: flex">
  30. <div class="key">Ctrl</div>
  31. <div class="key">X</div>
  32. </div>
  33. </Cell>
  34. <Cell title="粘贴">
  35. <div slot="extra" style="display: flex">
  36. <div class="key">Ctrl</div>
  37. <div class="key">V</div>
  38. </div>
  39. </Cell>
  40. <Cell title="撤销">
  41. <div slot="extra" style="display: flex">
  42. <div class="key">Ctrl</div>
  43. <div class="key">Z</div>
  44. </div>
  45. </Cell>
  46. <Cell title="撤回撤销">
  47. <div slot="extra" style="display: flex">
  48. <div class="key">Ctrl</div>
  49. <div class="key">Shift</div>
  50. <div class="key">Z</div>
  51. </div>
  52. </Cell>
  53. <Cell title="全选">
  54. <div slot="extra" style="display: flex">
  55. <div class="key">Ctrl</div>
  56. <div class="key">Alt</div>
  57. <div class="key">A</div>
  58. </div>
  59. </Cell>
  60. <Cell title="删除">
  61. <div slot="extra" style="display: flex">
  62. <div class="key">Del</div>
  63. </div>
  64. </Cell>
  65. <Cell title="放大">
  66. <div slot="extra" style="display: flex;align-items: center">
  67. <div class="key">Ctrl</div>
  68. <div class="key">Alt</div>
  69. <div class="key">+</div>
  70. <div style="padding-left:3px">或</div>
  71. <div class="key">Ctrl</div>
  72. <div style="padding-left:3px">+ 鼠标滚轮</div>
  73. </div>
  74. </Cell>
  75. <Cell title="缩小">
  76. <div slot="extra" style="display: flex">
  77. <div class="key">Ctrl</div>
  78. <div class="key">Alt</div>
  79. <div class="key">-</div>
  80. <div style="padding-left:3px">或</div>
  81. <div class="key">Ctrl</div>
  82. <div style="padding-left:3px">+ 鼠标滚轮</div>
  83. </div>
  84. </Cell>
  85. <Cell title="整体移动画布" extra="鼠标右键按住空白处拖动" />
  86. <Cell title="多选" extra="鼠标左键按住空白处框选" />
  87. <Cell title="移入节点组" extra="鼠标左键按住节点拖入" />
  88. <Cell title="移出节点组">
  89. <div slot="extra" style="display: flex;align-items: center">
  90. <div>按住</div>
  91. <div class="key">Ctrl</div>
  92. <div style="padding-left:3px">+ 鼠标左键按住节点拖出</div>
  93. </div>
  94. </Cell>
  95. <Cell title="调整路线形状">
  96. <div slot="extra" style="display: flex;align-items: center;">
  97. <div>按住</div>
  98. <div class="key">Ctrl</div>
  99. <div style="padding-left:3px">+ 鼠标左键拖动路线</div>
  100. </div>
  101. </Cell>
  102. </CellGroup>
  103. </Card>
  104. </div>
  105. </Poptip>
  106. <Tooltip content="节点居中">
  107. <Button icon="md-contract" @click="()=>{this.graph.centerContent(); this.graph.cleanSelection()}"></Button>
  108. </Tooltip>
  109. <Tooltip content="适应窗口">
  110. <Button icon="md-expand" @click="()=>{this.graph.zoomToFit(); this.graph.cleanSelection()}"></Button>
  111. </Tooltip>
  112. <Tooltip content="原始比例">
  113. <Button icon="iconfont iconfont icon-one2one" @click="()=>{this.graph.zoomTo(1); this.graph.cleanSelection()}"></Button>
  114. </Tooltip>
  115. <Tooltip content="显示/隐藏小地图">
  116. <Button icon="md-map" @click="()=>{this.showMiniMap=!this.showMiniMap}"></Button>
  117. </Tooltip>
  118. <Tooltip :content="leftMouseContent">
  119. <Button :icon="leftMouseIcon" @click="changeLeftMouse"></Button>
  120. </Tooltip>
  121. <Tooltip content="导出PNG">
  122. <Button icon="md-images" @click="()=>{this.graph.exportPNG('',{padding:50})}"></Button>
  123. </Tooltip>
  124. <Tooltip content="导出JSON">
  125. <Button icon="ios-cloud-download" @click="exportJson"></Button>
  126. </Tooltip>
  127. <Tooltip content="导入JSON">
  128. <Upload action="" accept=".json" :before-upload="uploadJson">
  129. <Button icon="ios-cloud-upload"></Button>
  130. </Upload>
  131. </Tooltip>
  132. </div>
  133. <div>
  134. <DkButton style="margin-right: 10px;" ref="save" type="primary" @click="save">{{ $t('save') }}</DkButton>
  135. <DkButton ref="close" @click="close('/process/process-flow/index')">{{ $t('close') }}</DkButton>
  136. </div>
  137. </Footer>
  138. </Layout>
  139. <!-- 缩放比例 -->
  140. <div class="scale">
  141. <InputNumber v-model="scaleValue"
  142. :min="scaleMin"
  143. :max="scaleMax"
  144. :step="0.1"
  145. controls-outside
  146. :editable="false"
  147. style="width: 180px"
  148. :formatter="value => `缩放比例:${(value * 100).toFixed(0)}%`"
  149. :parser="value => value.replace('%', '').replace('缩放比例:', '')"
  150. @on-change="(e)=>{this.graph.zoomTo(e)}"
  151. ></InputNumber>
  152. </div>
  153. <!-- 小地图 -->
  154. <transition name="fade">
  155. <div id="miniMap" ref="miniMap" class="miniMap" v-show="showMiniMap"/>
  156. </transition>
  157. <!-- 节点弹窗 -->
  158. <NodeModal key="node" v-if="process.nodeModal.display"
  159. :dataKindList="dataKindList"
  160. :productGradeList="productGradeList"
  161. :jobList="jobList"
  162. :shopList="shopList"
  163. :kilnList="kilnList"
  164. :whList="whList"
  165. :dictionaryDataList="dictionaryDataList"/>
  166. <!-- 连线弹窗 -->
  167. <EdgeModal key="edge" v-if="process.edgeModal.display"
  168. :dictionaryDataList="dictionaryDataList"
  169. :productGradeList="productGradeList.filter(it=>![$config.gradeKindType.decrease,$config.gradeKindType.inferior].includes(it.gradeKind))"/>
  170. </div>
  171. </template>
  172. <script>
  173. import { mapState, mapMutations } from 'vuex'
  174. import NodeModal from '_c/business/process/node-modal/node-modal'
  175. import EdgeModal from '_c/business/process/edge-modal/edge-modal'
  176. const insertCss = require('insert-css')
  177. import Process from '@/view/process/process-flow/config/ProcessConfig'
  178. import queryUtil from '@/view/process/process-flow/queryUtil'
  179. import { formMixin } from '@/mixins/form'
  180. import FileSaver from 'file-saver'
  181. import { Selection } from '@antv/x6-plugin-selection'
  182. export default {
  183. name: 'process-setting',
  184. mixins: [formMixin],
  185. components: { NodeModal, EdgeModal },
  186. props: {
  187. type: {
  188. type: String,
  189. default: 'edit'
  190. },
  191. },
  192. data() {
  193. return {
  194. showMiniMap:true,
  195. scaleValue: 1,
  196. scaleMax: 3,
  197. scaleMin: 0.5,
  198. graph: null,//图形对象
  199. exportData: undefined,
  200. importValue: undefined,
  201. dataKindList: [],//基础数据
  202. productGradeList: [],//产品等级
  203. jobList: [],//工种
  204. dictionaryDataList:[],//数据字典
  205. shopList:[],//车间
  206. kilnList:[],//窑炉
  207. whList:[],//仓库
  208. leftMouseContent:'点击切换左键移动画布',
  209. leftMouseIcon:'md-crop',
  210. }
  211. },
  212. created() {
  213. this.setCurrentNodeId(undefined)
  214. this.setCurrentEdgeId(undefined)
  215. this.setProcessNodeModalDisplay(null)
  216. this.setProcessEdgeModalDisplay(null)
  217. },
  218. mounted() {
  219. },
  220. activated(){
  221. },
  222. computed: {
  223. ...mapState(['process']),
  224. },
  225. methods: {
  226. ...mapMutations(['setProcessNodeModalDisplay', 'setProcessEdgeModalDisplay', 'setCurrentNodeId', 'setCurrentEdgeId']),
  227. changeLeftMouse(){
  228. console.log(this.graph)
  229. if(this.leftMouseIcon=='ios-hand'){
  230. this.leftMouseIcon='md-crop'
  231. this.leftMouseContent='点击切换左键移动画布'
  232. this.graph.panning.options.panning.eventTypes=['rightMouseDown']
  233. this.graph.toggleRubberband(true)
  234. }else{
  235. this.leftMouseIcon='ios-hand'
  236. this.leftMouseContent='点击切换左键框选主题'
  237. this.graph.panning.options.panning.eventTypes=['leftMouseDown','rightMouseDown']
  238. this.graph.toggleRubberband(false)
  239. }
  240. },
  241. /**
  242. * @desc : 导出json方法
  243. * @author : 张潇木
  244. * @date : 2023/5/10 9:52
  245. */
  246. exportJson(){
  247. // JSON.stringify(data, null, 2): 格式化json数据 方便阅读
  248. FileSaver.saveAs(new Blob([JSON.stringify(this.graph.toJSON(),null,2)], {type: 'application/json'}), 'flow.json')
  249. },
  250. /**
  251. * @desc : 导入json
  252. * @author : 张潇木
  253. * @date : 2023/5/10 10:17
  254. */
  255. uploadJson(file){
  256. //检验文件类型
  257. if(file.type!='application/json'){
  258. console.log('file.type',file.type)
  259. this.$Message.error('导入失败,请上传JSON类型的文件')
  260. return false
  261. }
  262. //读取json
  263. let reader = new FileReader()
  264. reader.readAsText(file)
  265. reader.onload = ((e) => {
  266. console.log('e',e)
  267. let uploadData = JSON.parse(e.target.result)
  268. console.log('uploadData',uploadData)
  269. if(!uploadData.cells){
  270. //校验数据结构
  271. this.$Message.error('导入失败,请检查JSON文件数据结构')
  272. }else{
  273. //根据数据绘制图形
  274. this.graph.fromJSON(uploadData)
  275. // region 暂时不考虑复杂场景,导入数据不需处理
  276. // let allCells=this.graph.getCells()
  277. // this.graph.cut(allCells)
  278. // this.graph.paste({ offset: 0 })
  279. // this.graph.cleanSelection()
  280. // endregion
  281. this.$Message.success('导入成功')
  282. }
  283. })
  284. return false
  285. },
  286. /**
  287. * @desc : 获取基础数据
  288. * @author : 张潇木
  289. * @date : 2023/1/31 13:42
  290. */
  291. initData() {
  292. // 获取产品等级
  293. this.excute(this.$service.productGradeService, this.$service.productGradeService.selectByCond, {
  294. flgValid: true,
  295. ftyId: this.$store.state.user.ftyId
  296. }).then(res => {
  297. if (res.code === this.$config.SUCCESS_CODE) {
  298. this.productGradeList = res.data.list
  299. }
  300. })
  301. // 获取工种信息
  302. this.excute(this.$service.jobService, this.$service.jobService.selectByCond, {
  303. flgValid: true,
  304. ftyId: this.$store.state.user.ftyId
  305. }).then(res => {
  306. if (res.code === this.$config.SUCCESS_CODE) {
  307. this.jobList = res.data.list
  308. }
  309. })
  310. //数据字典
  311. this.excute(this.$service.commonService, this.$service.commonService.getDictionaryData, {
  312. ftyId: this.$store.state.user.ftyId,
  313. }).then(res => {
  314. if (res.code === this.$config.SUCCESS_CODE) {
  315. this.dictionaryDataList = res.data
  316. }
  317. })
  318. //车间
  319. this.excute(this.$service.commonService, this.$service.commonService.getFactorySpace, {
  320. ftyId: this.$store.state.user.ftyId,
  321. spaceKind: this.$config.factorySpace.shop
  322. }).then(res => {
  323. if (res.code === this.$config.SUCCESS_CODE) {
  324. this.shopList = res.data
  325. }
  326. })
  327. //窑炉
  328. this.excute(this.$service.equipKilnService, this.$service.equipKilnService.selectByCond, {
  329. ftyId: this.$store.state.user.ftyId,
  330. flgValid: true,
  331. }).then(res => {
  332. if (res.code === this.$config.SUCCESS_CODE) {
  333. this.kilnList = res.data.list
  334. }
  335. })
  336. //仓库
  337. this.excute(this.$service.warehouseService, this.$service.warehouseService.selectByCond, {
  338. ftyId: this.$store.state.user.ftyId,
  339. flgValid: true,
  340. }).then(res => {
  341. if (res.code === this.$config.SUCCESS_CODE) {
  342. this.whList = res.data.list
  343. }
  344. })
  345. },
  346. clearMiniMap(){
  347. document.getElementsByClassName('x6-widget-minimap')?.[0]?.remove()
  348. },
  349. /**
  350. * @desc : 初始化流程设计器
  351. * @author : 张潇木
  352. * @date : 2023/7/14 16:22
  353. */
  354. initGraph(){
  355. this.clearMiniMap()
  356. //创建流程图对象
  357. this.graph = Process.init(this.$refs.container,this.$refs.miniMap,this.dataKindList.filter(it=>it.kindType===this.$config.dataKind.nodeKind))
  358. //监听删除节点
  359. this.bindDeleteNodes()
  360. //监听画布缩放
  361. this.bindGraphScale()
  362. //初始化数据
  363. this.graph.fromJSON(this.formData.flowLayout || { cells: [] })
  364. //再重新渲染群组大小
  365. this.graph.getNodes().filter(it => it.shape == 'groupNode').forEach((it) => {
  366. // console.log('group-data',it.getData())
  367. //解构
  368. let { isCollapsed, expandSize } = it.getData()
  369. //设置展开大小
  370. it.setExpandSize(expandSize)
  371. //如果不是收起的,展开并还原大小
  372. if (!isCollapsed) {
  373. it.toggleCollapse(isCollapsed)
  374. }
  375. })
  376. },
  377. /**
  378. * @desc : 提交保存
  379. * @author : 张潇木
  380. * @date : 2023/2/3 9:30
  381. */
  382. save() {
  383. //取消动画
  384. let allEdges=this.graph.getEdges()
  385. allEdges?.forEach((edge) => {
  386. edge.attr('line/style/animation', '')
  387. })
  388. //节点组大小和是否展开存在data中
  389. this.graph.getNodes().filter(it => it.shape == 'groupNode').forEach((it) => {
  390. //如果是收起状态,存展开大小,如果展开,存当时的实际大小
  391. it.setData({
  392. 'expandSize': it.isCollapsed() ? it.getExpandSize() : it.getSize(),
  393. 'isCollapsed': it.isCollapsed()
  394. })
  395. })
  396. //转json
  397. this.formData.flowLayout = this.graph.toJSON()
  398. //流程整体校验
  399. if (!this.validData()) return false
  400. //发送保存网络请求
  401. this.excute(this.$service.processService, this.$service.processService.processSetting, this.formData).then(res => {
  402. if (res.code === this.$config.SUCCESS_CODE) {
  403. // 提示信息
  404. this.$Message.success(this.$t('I_001', { 'param': this.$v(this.type) }))
  405. //触发首页查询
  406. queryUtil.$emit('process-setting-ok', { row: this.formData })
  407. // 编辑关闭窗体
  408. this.close(false);
  409. } else {
  410. // 如果不成功就提示错误信息
  411. this.$Message.warning(res.message)
  412. }
  413. })
  414. },
  415. /**
  416. * @desc : 校验数据
  417. * @author : 张潇木
  418. * @date : 2023/2/27 11:12
  419. */
  420. validData() {
  421. let allNodes = this.graph.getNodes().filter(it => it.shape == 'custom-image')
  422. let allEdges = this.graph.getEdges()
  423. let startNodes = allNodes.filter(it=>it.getData()?.flowKind===this.$config.flowKind.start)
  424. let endNodes = allNodes.filter(it=>it.getData()?.flowKind===this.$config.flowKind.end)
  425. //成检交接节点
  426. let nodeSysTagsCheck =allNodes.filter(it=>it.getData()?.nodeSysTags?.includes(this.$config.nodeSysTags.check))
  427. if(allNodes.length<2){
  428. this.$Message.warning('流程中应至少包含2个节点')
  429. return false
  430. }
  431. if(allEdges.length<1){
  432. this.$Message.warning('流程中应至少包含1条线')
  433. return false
  434. }
  435. if(startNodes.length<1){
  436. this.$Message.warning('流程中应至少包含1个开始节点')
  437. return false
  438. }
  439. if(endNodes.length<1){
  440. this.$Message.warning('流程中应至少包含1个结束节点')
  441. return false
  442. }
  443. if(nodeSysTagsCheck.length<1){
  444. this.$Message.warning('流程中应至少包含1个 [工序标签] 为 [成检交接] 的节点')
  445. return false
  446. }
  447. console.log('allNodes',allNodes)
  448. //检查所有开始节点是否能够连接到结束节点
  449. let startNodesNoCloseLoop=startNodes.filter(it=>{
  450. let endCount = this.graph.getSuccessors(it)?.filter(it=>it.getData()?.flowKind===this.$config.flowKind.end)
  451. if (endCount<1) {
  452. this.$Message.warning('开始节点为 [' + it.getData()?.nodeName + '] 的流程未闭环,请检查')
  453. return true
  454. }
  455. })
  456. if (startNodesNoCloseLoop.length > 0) return false
  457. //检查所有结束节点是否都有开始节点(回收不校验)
  458. let endNodesNoCloseLoop=endNodes.filter(it=>it.getData()?.nodeKind!==this.$config.nodeKind.recover).filter(it=>{
  459. let startCount = this.graph.getPredecessors(it)?.filter(it=>it.getData()?.flowKind===this.$config.flowKind.start)
  460. if (startCount<1) {
  461. this.$Message.warning('结束节点为 [' + it.getData()?.nodeName + '] 的流程未闭环,请检查')
  462. return true
  463. }
  464. })
  465. if (endNodesNoCloseLoop.length > 0) return false
  466. //节点的单个校验未通过
  467. let invalidNodes =allNodes.filter(it => {
  468. if (!it.getData().isValid) {
  469. this.$Message.warning('[' + it.getData()?.nodeName + '] 节点设置有误,请检查')
  470. return true
  471. }
  472. })
  473. if (invalidNodes.length > 0) return false
  474. return true
  475. },
  476. /**
  477. * @desc : 删除节点特殊控制,如果是成型模型,且被成型线绑定了,则不能删除
  478. * @author : 张潇木
  479. * @date : 2023/3/29 13:26
  480. */
  481. bindDeleteNodes(){
  482. this.graph.bindKey(['backspace','del'], () => {
  483. const cells = this.graph.getSelectedCells()
  484. if (cells.length) {
  485. //取成型节点id
  486. let shapingNodes=cells.filter(it=>it.getData()?.nodeKind === this.$config.nodeKind.shaping).map(it=> {return it.getData()?.nodeId})
  487. if(shapingNodes.length){
  488. //查询是否存在绑定的成型线
  489. this.excute(this.$service.processService, this.$service.processService.getBindMolding, shapingNodes).then(res => {
  490. if (res.code === this.$config.SUCCESS_CODE&&res.data.length) {
  491. this.$Message.warning('无法删除已被成型线绑定的节点')
  492. }
  493. else{
  494. this.graph.removeCells(cells)
  495. }
  496. })
  497. }else{
  498. this.graph.removeCells(cells)
  499. }
  500. }
  501. })
  502. },
  503. /**
  504. * @desc : 监听画布缩放
  505. * @author : 张潇木
  506. * @date : 2023/7/14 10:42
  507. */
  508. bindGraphScale() {
  509. this.graph.on('scale', ({ sx, sy, ox, oy }) => {
  510. this.scaleValue=sx
  511. })
  512. },
  513. /**
  514. * @desc : 查询明细
  515. * @author : 张潇木
  516. * @date : 2023/2/3 16:47
  517. */
  518. detail(id) {
  519. return this.excuteNoParam(this.$service.processService, this.$service.processService.selectById, [id], false)
  520. },
  521. /**
  522. * @desc : formData赋值
  523. * @author : 张潇木
  524. * @date : 2023/2/7 8:50
  525. */
  526. setValuesByEdit(data) {
  527. this.formData = data
  528. // 获取数据类别
  529. this.excute(this.$service.commonService, this.$service.commonService.getDataKind, {}).then(res => {
  530. if (res.code === this.$config.SUCCESS_CODE) {
  531. this.dataKindList = res.data
  532. //图形的初始化依赖于数据种类,需要根据DB变化名称等信息
  533. this.initGraph();
  534. }
  535. })
  536. },
  537. },
  538. }
  539. </script>
  540. <style scoped>
  541. #container {
  542. display: flex;
  543. border: 1px solid #dfe3e8;
  544. }
  545. #stencil {
  546. width: 180px;
  547. height: 100%;
  548. position: relative;
  549. border-right: 1px solid #dfe3e8;
  550. background-color: #f5f5f5;
  551. }
  552. #graph-container {
  553. width: calc(100% - 180px);
  554. height: 100%;
  555. }
  556. .x6-widget-stencil {
  557. background-color: #fff;
  558. }
  559. .x6-widget-stencil-title {
  560. background-color: #fff;
  561. }
  562. .x6-widget-stencil-group-title {
  563. background-color: #fff !important;
  564. }
  565. /deep/ .x6-widget-transform {
  566. margin: -1px 0 0 -1px;
  567. padding: 0px;
  568. border: 1px solid #239edd;
  569. }
  570. /deep/ .x6-widget-transform > div {
  571. border: 1px solid #239edd;
  572. }
  573. /deep/ .x6-widget-transform > div:hover {
  574. background-color: #3dafe4;
  575. }
  576. /deep/ .x6-widget-transform-active-handle {
  577. background-color: #3dafe4;
  578. }
  579. /deep/ .x6-widget-transform-resize {
  580. border-radius: 0;
  581. }
  582. /deep/ .x6-widget-selection-inner {
  583. border: 1px solid #239edd;
  584. }
  585. /deep/ .x6-widget-selection-box {
  586. border: 0 !important;
  587. }
  588. /*@keyframes ant-line {*/
  589. /* to {*/
  590. /* stroke-dashoffset: -1000*/
  591. /* }*/
  592. /*}*/
  593. .snap-line-color {
  594. color: black !important;
  595. background: black !important;
  596. }
  597. .ivu-layout-has-sider {
  598. height: 100%;
  599. }
  600. .header {
  601. height: 30px;
  602. background: #ededed;
  603. display: flex;
  604. align-items: center;
  605. justify-content: space-between;
  606. }
  607. /deep/ .ivu-layout-header {
  608. height: 52px !important;
  609. line-height: 52px !important;
  610. }
  611. .footer {
  612. /*background: #fff;*/
  613. display: flex;
  614. justify-content: space-between;
  615. align-items: center;
  616. padding: 10px 30px 10px 180px;
  617. position: fixed;
  618. bottom: 0;
  619. width: calc(100% - 200px);
  620. }
  621. .key{
  622. align-items: center;
  623. background-image: linear-gradient(180deg,#f2f4f5,#fff);
  624. border: 1px solid #d1d5d9;
  625. border-radius: 4px;
  626. box-shadow: 0 1px 0 0 #b8bfc4, inset 0 2px 0 0 #fff;
  627. color: #666;
  628. display: flex;
  629. font-size: 12px;
  630. font-weight: 500;
  631. height: 20px;
  632. justify-content: center;
  633. margin-left: 5px;
  634. min-width: 20px;
  635. padding: 0 5px;
  636. }
  637. /deep/ .ivu-card-head{
  638. padding: 7px 8px!important;
  639. }
  640. /deep/ .ivu-cell{
  641. padding: 3px 8px!important;
  642. }
  643. /deep/ .ivu-cell-group{
  644. padding: 2px 0 !important;
  645. }
  646. /deep/ .ivu-btn-icon-only{
  647. padding: 0 !important;
  648. font-size: 28px!important;
  649. width: 48px!important;
  650. height: 48px!important;
  651. border: none!important;
  652. outline:none!important; /*去除点击时的蓝色边框*/
  653. box-shadow:none!important; /*同时去除阴影的蓝色边框*/
  654. background: #F5F5F5;
  655. /*border-radius:0px!important;*/
  656. }
  657. /deep/ .iconfont{
  658. font-size: 28px!important;
  659. /*font-weight: bold;*/
  660. }
  661. /deep/ .ivu-tooltip{
  662. height: 48px!important;
  663. }
  664. /deep/ .custom-html{
  665. height: 100%;
  666. width: 100%;
  667. display: flex;
  668. border:solid 1px #E9F1FF;
  669. }
  670. /deep/ .custom-html-left{
  671. background: #E9F1FF;
  672. height: 100%;
  673. width: 52px;
  674. border: solid 2px #E9F1FF;
  675. border-right: none;
  676. border-top-left-radius: 10px;
  677. border-bottom-left-radius: 10px;
  678. display: flex;
  679. align-items: center;
  680. justify-content: center;
  681. box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1);
  682. }
  683. /deep/ .custom-html-right{
  684. background: #fff;
  685. height: 100%;
  686. /*width: 60%;*/
  687. border: solid 2px #fff;
  688. border-left: none;
  689. border-top-right-radius: 10px;
  690. border-bottom-right-radius: 10px;
  691. box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1);
  692. overflow: hidden;
  693. flex: 1;
  694. }
  695. /deep/ .custom-html-right-title{
  696. font-size: 14px;
  697. font-weight: bold;
  698. padding-left: 10px;
  699. width: 100%;
  700. height: 50%;
  701. padding-top: 6px;
  702. align-items: center;
  703. color: #4C4C4C;
  704. overflow: hidden;
  705. text-overflow:ellipsis;
  706. white-space: nowrap;
  707. }
  708. /deep/ .custom-html-right-text{
  709. padding: 3px 0 0 10px ;
  710. width: 100%;
  711. height: 50%;
  712. font-size: 10px;
  713. display: flex;
  714. align-items: self-start;
  715. color: #B6B6B6;
  716. }
  717. .tools{
  718. background: #F2F7FA;
  719. }
  720. .scale{
  721. position: absolute;
  722. right: 30px;
  723. top: 30px
  724. }
  725. /deep/ .scale .ivu-input-number-controls-outside-btn i {
  726. font-size: 18px;
  727. font-weight: bold;
  728. }
  729. /deep/ .scale .ivu-input-number-input{
  730. text-align: center!important;
  731. }
  732. .miniMap{
  733. position: absolute;
  734. bottom: 100px;
  735. right: 30px
  736. }
  737. .fade-enter,.fade-leave-to {
  738. opacity: 0;
  739. }
  740. .fade-enter-to,.fade-leave {
  741. opacity: 1;
  742. }
  743. .fade-enter-active,.fade-leave-active {
  744. transition: all .2s;
  745. }
  746. </style>