edit.vue 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. <template>
  2. <div class="w-main docs-edit">
  3. <v-title>{{$L('文档编辑')}}-{{$L('轻量级的团队在线协作')}}</v-title>
  4. <div class="edit-box">
  5. <div class="edit-header">
  6. <div class="header-menu active" @click="handleClick('back')"><Icon type="md-arrow-back" /></div>
  7. <Tooltip class="header-menu" :content="$L('知识库目录')">
  8. <div class="menu-container" @click="handleClick('menu')"><Icon type="md-menu" /></div>
  9. </Tooltip>
  10. <Tooltip class="header-menu" :content="$L('分享文档')">
  11. <div class="menu-container" @click="handleClick('share')"><Icon type="md-share" /></div>
  12. </Tooltip>
  13. <Tooltip class="header-menu" :content="$L('浏览文档')">
  14. <a class="menu-container" target="_blank" :href="handleClick('view')"><Icon type="md-eye" /></a>
  15. </Tooltip>
  16. <Tooltip class="header-menu" :content="$L('历史版本')">
  17. <div class="menu-container" @click="handleClick('history')"><Icon type="md-time" /></div>
  18. </Tooltip>
  19. <Poptip class="header-menu synch">
  20. <div class="menu-container">
  21. <Icon type="md-contacts" :title="$L('正在协作会员')"/><em v-if="synchUsers.length > 0">{{synchUsers.length}}</em>
  22. </div>
  23. <ul class="synch-lists" slot="content">
  24. <li class="title">{{$L('正在协作会员')}}:</li>
  25. <li v-for="(item, key) in synchUsersS" :key="key" @click="handleSynch(item.username)">
  26. <UserImg :info="item" class="synch-userimg"/>
  27. <UserView class="synch-username" placement="right" :username="item.username"/>
  28. <span v-if="item.username==userInfo.username" class="synch-self">{{$L('自己')}}</span>
  29. </li>
  30. </ul>
  31. </Poptip>
  32. <Tooltip class="header-menu" :class="{lock:isLock}" max-width="500">
  33. <div slot="content" style="white-space:nowrap">
  34. <span v-if="isLock&&docDetail.lockname!=userInfo.username">【<UserView :username="docDetail.lockname"/>】{{$L('已锁定')}}</span>
  35. <span v-else>{{$L('锁定后其他会员将无法修改保存文档。')}}</span>
  36. </div>
  37. <div class="menu-container" @click="handleClick(isLock?'unlock':'lock')"><Icon :type="isLock?'md-lock':'md-unlock'" /></div>
  38. </Tooltip>
  39. <div class="header-title">{{docDetail.title}}</div>
  40. <div v-if="docDetail.type=='document'" class="header-hint">
  41. <ButtonGroup size="small" shape="circle">
  42. <Button :type="`${docContent.type!='md'?'primary':'default'}`" @click="$set(docContent, 'type', 'text')">{{$L('文本编辑器')}}</Button>
  43. <Button :type="`${docContent.type=='md'?'primary':'default'}`" @click="$set(docContent, 'type', 'md')">{{$L('MD编辑器')}}</Button>
  44. </ButtonGroup>
  45. </div>
  46. <div v-if="docDetail.type=='mind'" class="header-hint">
  47. {{$L('选中节点,按enter键添加同级节点,tab键添加子节点')}}
  48. </div>
  49. <Dropdown v-if="docDetail.type=='mind' || docDetail.type=='flow' || docDetail.type=='sheet'"
  50. trigger="click"
  51. class="header-hint"
  52. @on-click="exportMenu">
  53. <a href="javascript:void(0)">
  54. {{$L('导出')}}
  55. <Icon type="ios-arrow-down"></Icon>
  56. </a>
  57. <DropdownMenu v-if="docDetail.type=='sheet'" slot="list">
  58. <DropdownItem name="xlsx">{{$L('导出XLSX')}}</DropdownItem>
  59. <DropdownItem name="xlml">{{$L('导出XLS')}}</DropdownItem>
  60. <DropdownItem name="csv">{{$L('导出CSV')}}</DropdownItem>
  61. <DropdownItem name="txt">{{$L('导出TXT')}}</DropdownItem>
  62. </DropdownMenu>
  63. <DropdownMenu v-else slot="list">
  64. <DropdownItem name="png">{{$L('导出PNG图片')}}</DropdownItem>
  65. <DropdownItem name="pdf">{{$L('导出PDF文件')}}</DropdownItem>
  66. </DropdownMenu>
  67. </Dropdown>
  68. <Button :disabled="equalContent" :loading="loadIng > 0" class="header-button" size="small" type="primary" @click="handleClick('save')">{{$L('保存')}}</Button>
  69. </div>
  70. <div class="docs-body">
  71. <template v-if="docDetail.type=='document'">
  72. <MDEditor v-if="docContent.type=='md'" class="body-text" v-model="docContent.content" height="100%"></MDEditor>
  73. <TEditor v-else class="body-text" v-model="docContent.content" height="100%"></TEditor>
  74. </template>
  75. <minder v-else-if="docDetail.type=='mind'" ref="myMind" class="body-mind" v-model="docContent"></minder>
  76. <sheet v-else-if="docDetail.type=='sheet'" ref="mySheet" class="body-sheet" v-model="docContent.content"></sheet>
  77. <flow v-else-if="docDetail.type=='flow'" ref="myFlow" class="body-flow" v-model="docContent.content"></flow>
  78. </div>
  79. </div>
  80. <WDrawer v-model="docDrawerShow" maxWidth="450">
  81. <Tabs v-if="docDrawerShow" v-model="docDrawerTab">
  82. <TabPane :label="$L('知识库目录')" name="menu">
  83. <nested-draggable :lists="sectionLists" :readonly="true" :activeid="sid" @change="handleSection"></nested-draggable>
  84. <div v-if="sectionLists.length == 0" style="color:#888;padding:32px;text-align:center">{{sectionNoDataText}}</div>
  85. </TabPane>
  86. <TabPane :label="$L('文档历史版本')" name="history">
  87. <Table class="tableFill" :columns="historyColumns" :data="historyLists" :no-data-text="historyNoDataText" size="small" stripe></Table>
  88. </TabPane>
  89. </Tabs>
  90. </WDrawer>
  91. </div>
  92. </template>
  93. <style lang="scss">
  94. .docs-edit {
  95. .body-text {
  96. .mdeditor-box {
  97. position: relative;
  98. width: 100%;
  99. .markdown {
  100. position: absolute;
  101. top: 0;
  102. left: 0;
  103. bottom: 0;
  104. right: 0;
  105. overflow: auto;
  106. transform: translateZ(0);
  107. &.border {
  108. border: 0 !important;
  109. }
  110. }
  111. }
  112. .teditor-loadedstyle {
  113. .tox-tinymce {
  114. border: 0;
  115. border-radius: 0;
  116. }
  117. .tox-mbtn {
  118. height: 28px;
  119. }
  120. .tox-menubar,
  121. .tox-toolbar-overlord {
  122. padding: 0 12%;
  123. background: #f9f9f9;
  124. }
  125. .tox-toolbar__overflow,
  126. .tox-toolbar__primary {
  127. background: none !important;
  128. border-top: 1px solid #eaeaea !important;
  129. }
  130. .tox-toolbar-overlord {
  131. border-bottom: 1px solid #E9E9E9 !important;
  132. }
  133. .tox-toolbar__group:not(:last-of-type) {
  134. border-right: 1px solid #eaeaea !important;
  135. }
  136. .tox-sidebar-wrap {
  137. margin: 22px 12%;
  138. border: 1px solid #e8e8e8;
  139. border-radius: 2px;
  140. box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.08);
  141. .tox-edit-area {
  142. border-top: 0;
  143. }
  144. }
  145. .tox-statusbar {
  146. border-top: 1px solid #E9E9E9;
  147. .tox-statusbar__resize-handle {
  148. display: none;
  149. }
  150. }
  151. }
  152. }
  153. .body-sheet {
  154. box-sizing: content-box;
  155. * {
  156. box-sizing: content-box;
  157. }
  158. }
  159. }
  160. </style>
  161. <style lang="scss" scoped>
  162. .docs-edit {
  163. .edit-box {
  164. display: flex;
  165. flex-direction: column;
  166. position: absolute;
  167. width: 100%;
  168. height: 100%;
  169. overflow-x: auto;
  170. .edit-header {
  171. display: flex;
  172. flex-direction: row;
  173. align-items: center;
  174. width: 100%;
  175. height: 38px;
  176. min-width: 1024px;
  177. background-color: #ffffff;
  178. box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.1);
  179. position: relative;
  180. z-index: 99;
  181. .header-menu {
  182. width: 48px;
  183. height: 100%;
  184. text-align: center;
  185. display: flex;
  186. align-items: center;
  187. justify-content: center;
  188. margin-right: 3px;
  189. cursor: pointer;
  190. position: relative;
  191. .menu-container {
  192. display: inline-block;
  193. width: 48px;
  194. height: 38px;
  195. line-height: 38px;
  196. color: #777777;
  197. transition: color .2s ease;
  198. }
  199. .ivu-icon {
  200. font-size: 16px;
  201. }
  202. &.synch {
  203. .menu-container {
  204. em {
  205. padding-left: 2px;
  206. }
  207. }
  208. }
  209. &.lock {
  210. .menu-container {
  211. color: #059DFD;
  212. }
  213. }
  214. &:hover,
  215. &.active {
  216. color: #fff;
  217. background: #059DFD;
  218. .menu-container {
  219. color: #fff;
  220. }
  221. }
  222. .synch-lists {
  223. max-height: 500px;
  224. overflow: auto;
  225. li {
  226. display: flex;
  227. align-items: center;
  228. padding: 6px 0;
  229. border-bottom: 1px dashed #eeeeee;
  230. &.title {
  231. font-size: 14px;
  232. font-weight: 600;
  233. color: #333333;
  234. }
  235. .synch-userimg {
  236. width: 24px;
  237. height: 24px;
  238. font-size: 14px;
  239. line-height: 24px;
  240. border-radius: 12px;
  241. }
  242. .synch-self {
  243. padding: 1px 3px;
  244. margin-left: 5px;
  245. height: 18px;
  246. line-height: 16px;
  247. background-color: #FF5722;
  248. color: #ffffff;
  249. font-size: 12px;
  250. border-radius: 3px;
  251. transform: scale(0.95);
  252. }
  253. .synch-username {
  254. padding-left: 8px;
  255. font-size: 14px;
  256. color: #555555;
  257. }
  258. }
  259. }
  260. }
  261. .header-title {
  262. flex: 1;
  263. color: #333333;
  264. border-left: 1px solid #ddd;
  265. margin-left: 5px;
  266. padding-left: 24px;
  267. padding-right: 24px;
  268. font-size: 16px;
  269. overflow: hidden;
  270. text-overflow:ellipsis;
  271. white-space: nowrap;
  272. }
  273. .header-hint {
  274. padding-right: 22px;
  275. font-size: 12px;
  276. color: #666;
  277. white-space: nowrap;
  278. .ivu-btn {
  279. font-size: 12px;
  280. padding: 0 10px;
  281. }
  282. .ivu-dropdown-item {
  283. font-size: 12px !important;
  284. }
  285. }
  286. .header-button {
  287. font-size: 12px;
  288. margin-right: 12px;
  289. }
  290. }
  291. .docs-body {
  292. flex: 1;
  293. width: 100%;
  294. min-width: 1024px;
  295. position: relative;
  296. .body-text {
  297. display: flex;
  298. width: 100%;
  299. height: 100%;
  300. .teditor-loadedstyle {
  301. height: 100%;
  302. }
  303. }
  304. }
  305. }
  306. }
  307. </style>
  308. <script>
  309. import Vue from 'vue'
  310. import minder from '../../components/docs/minder'
  311. Vue.use(minder)
  312. const MDEditor = resolve => require(['../../components/MDEditor/index'], resolve);
  313. const TEditor = resolve => require(['../../components/TEditor'], resolve);
  314. const Sheet = resolve => require(['../../components/docs/sheet/index'], resolve);
  315. const Flow = resolve => require(['../../components/docs/flow/index'], resolve);
  316. const NestedDraggable = resolve => require(['../../components/docs/NestedDraggable'], resolve);
  317. const WDrawer = resolve => require(['../../components/iview/WDrawer'], resolve);
  318. export default {
  319. components: {WDrawer, Flow, Sheet, MDEditor, TEditor, NestedDraggable},
  320. data () {
  321. return {
  322. loadIng: 0,
  323. sid: 0,
  324. hid: 0,
  325. docDetail: { },
  326. docContent: { },
  327. bakContent: null,
  328. docDrawerShow: false,
  329. docDrawerTab: '',
  330. sectionLists: [],
  331. sectionNoDataText: "",
  332. historyColumns: [],
  333. historyLists: [],
  334. historyNoDataText: "",
  335. userInfo: {},
  336. routeName: '',
  337. synergyNum: 0,
  338. synchUsers: [],
  339. timeValue: Math.round(new Date().getTime() / 1000),
  340. }
  341. },
  342. created() {
  343. this.historyColumns = [{
  344. "title": this.$L("存档日期"),
  345. "minWidth": 160,
  346. "maxWidth": 200,
  347. render: (h, params) => {
  348. return h('span', $A.formatDate("Y-m-d H:i:s", params.row.indate));
  349. }
  350. }, {
  351. "title": this.$L("操作员"),
  352. "key": 'username',
  353. "minWidth": 80,
  354. "maxWidth": 130,
  355. render: (h, params) => {
  356. return h('UserView', {
  357. props: {
  358. username: params.row.username
  359. }
  360. });
  361. }
  362. }, {
  363. "title": " ",
  364. "key": 'action',
  365. "width": 80,
  366. "align": 'center',
  367. render: (h, params) => {
  368. if (this.hid == params.row.id || (this.hid == 0 && params.index == 0)) {
  369. return h('Icon', {
  370. props: { type: 'md-checkmark' },
  371. style: { marginRight: '6px', fontSize: '16px', color: '#FF5722' },
  372. });
  373. }
  374. return h('Button', {
  375. props: {
  376. type: 'text',
  377. size: 'small'
  378. },
  379. style: {
  380. fontSize: '12px'
  381. },
  382. on: {
  383. click: () => {
  384. let data = {sid: this.getSid() + "-" + params.row.id, other: this.$route.params.other}
  385. if (params.index == 0) {
  386. data.sid = this.getSid();
  387. }
  388. this.handleSection('openBefore', data);
  389. }
  390. }
  391. }, this.$L('还原'));
  392. }
  393. }];
  394. },
  395. mounted() {
  396. this.routeName = this.$route.name;
  397. this.userInfo = $A.getUserInfo((res, isLogin) => {
  398. this.userInfo = res;
  399. }, false);
  400. //
  401. setInterval(() => {
  402. if (this.routeName === this.$route.name) {
  403. this.timeValue = Math.round(new Date().getTime() / 1000);
  404. }
  405. });
  406. //
  407. $(window).bind('beforeunload', () => {
  408. if (!this.equalContent && this.routeName === this.$route.name) {
  409. return '是否放弃修改的内容返回?';
  410. }
  411. });
  412. //
  413. $A.WSOB.setOnMsgListener("chat/index", ['docs'], (msgDetail) => {
  414. if (this.routeName !== this.$route.name) {
  415. return;
  416. }
  417. let body = msgDetail.body;
  418. if (body.sid != this.sid) {
  419. return;
  420. }
  421. switch (body.type) {
  422. case 'users':
  423. this.synchUsers = body.lists;
  424. this.synchUsers.splice(this.synchUsers.length);
  425. break;
  426. case 'update':
  427. this.$Modal.confirm({
  428. title: this.$L("更新提示"),
  429. content: this.$L('团队成员(%)更新了内容,<br/>更新时间:%。<br/><br/>点击【确定】加载最新内容。', body.nickname, $A.formatDate("Y-m-d H:i:s", body.time)),
  430. onOk: () => {
  431. this.refreshDetail();
  432. }
  433. });
  434. break;
  435. case 'lock':
  436. case 'unlock':
  437. if (this.docDetail.lockname == body.lockname) {
  438. return;
  439. }
  440. this.$set(this.docDetail, 'lockname', body.lockname);
  441. this.$set(this.docDetail, 'lockdate', body.lockdate);
  442. this.$Notice.close('docs-lock')
  443. this.$Notice[body.type=='lock'?'warning':'info']({
  444. name: 'docs-lock',
  445. duration: 0,
  446. render: h => {
  447. return h('div', {
  448. style: {
  449. lineHeight: '18px'
  450. }
  451. }, [
  452. h('span', {
  453. style: {
  454. fontWeight: 500
  455. }
  456. }, body.nickname + ':'),
  457. h('span', {
  458. style: {
  459. paddingLeft: '6px'
  460. }
  461. }, this.$L(body.type == 'lock' ? '锁定文档' : '解锁文档'))
  462. ])
  463. }
  464. });
  465. break;
  466. }
  467. });
  468. },
  469. activated() {
  470. this.docDrawerTab = '';
  471. this.sectionNoDataText = '';
  472. this.historyNoDataText = '';
  473. //
  474. this.refreshSid();
  475. this.synergy(true);
  476. },
  477. deactivated() {
  478. if (this.isLock && this.docDetail.lockname == this.userInfo.username) {
  479. this.docDetail.lockname = '';
  480. this.handleClick('unlock');
  481. }
  482. this.$Notice.close('docs-lock');
  483. //
  484. if (!this.equalContent) {
  485. this.handleClick('save');
  486. }
  487. //
  488. this.synergy(false);
  489. this.docDrawerShow = false;
  490. if ($A.getToken() === false) {
  491. this.sid = 0;
  492. }
  493. },
  494. watch: {
  495. sid(val) {
  496. if (!val) {
  497. this.goBackDirect();
  498. return;
  499. }
  500. this.hid = $A.runNum($A.strExists(val, '-') ? $A.getMiddle(val, "-", null) : 0);
  501. this.refreshDetail();
  502. },
  503. docDrawerTab(act) {
  504. switch (act) {
  505. case "menu":
  506. if (!this.sectionNoDataText) {
  507. this.sectionNoDataText = this.$L("数据加载中.....");
  508. let bookid = this.docDetail.bookid;
  509. $A.apiAjax({
  510. url: 'docs/section/lists',
  511. data: {
  512. act: 'edit',
  513. bookid: bookid
  514. },
  515. error: () => {
  516. if (bookid != this.docDetail.bookid) {
  517. return;
  518. }
  519. this.sectionNoDataText = this.$L("数据加载失败!");
  520. },
  521. success: (res) => {
  522. if (bookid != this.docDetail.bookid) {
  523. return;
  524. }
  525. if (res.ret === 1) {
  526. this.sectionLists = res.data.tree;
  527. this.sectionNoDataText = this.$L("没有相关的数据");
  528. }else{
  529. this.sectionLists = [];
  530. this.sectionNoDataText = res.msg;
  531. }
  532. }
  533. });
  534. }
  535. break;
  536. case "history":
  537. if (!this.historyNoDataText) {
  538. this.historyNoDataText = this.$L("数据加载中.....");
  539. let sid = this.getSid();
  540. $A.apiAjax({
  541. url: 'docs/section/history',
  542. data: {
  543. id: sid,
  544. pagesize: 50
  545. },
  546. error: () => {
  547. if (sid != this.getSid()) {
  548. return;
  549. }
  550. this.historyNoDataText = this.$L("数据加载失败!");
  551. },
  552. success: (res) => {
  553. if (sid != this.getSid()) {
  554. return;
  555. }
  556. if (res.ret === 1) {
  557. this.historyLists = res.data;
  558. this.historyNoDataText = this.$L("没有相关的数据");
  559. }else{
  560. this.historyLists = [];
  561. this.historyNoDataText = res.msg;
  562. }
  563. }
  564. });
  565. }
  566. break;
  567. }
  568. }
  569. },
  570. computed: {
  571. equalContent() {
  572. return this.bakContent == $A.jsonStringify(this.docContent);
  573. },
  574. synchUsersS() {
  575. return this.synchUsers.filter(item => {
  576. return item.indate + 20 > this.timeValue;
  577. });
  578. },
  579. isLock() {
  580. return !!(this.docDetail.lockname && this.docDetail.lockdate > this.timeValue - 60);
  581. }
  582. },
  583. methods: {
  584. goBackDirect() {
  585. this.bakContent = $A.jsonStringify(this.docContent);
  586. this.goBack({name:'docs'});
  587. },
  588. synergy(enter) {
  589. if (enter === false) {
  590. $A.WSOB.sendTo('docs', {
  591. type: 'quit',
  592. sid: this.sid,
  593. username: this.userInfo.username,
  594. });
  595. } else {
  596. if (this.routeName !== this.$route.name) {
  597. let tmpNum = this.synergyNum;
  598. setTimeout(() => {
  599. if (tmpNum === this.synergyNum) {
  600. this.synergyNum++;
  601. this.synergy();
  602. }
  603. }, 10000);
  604. } else {
  605. $A.WSOB.sendTo('docs', null, {
  606. type: enter === true ? 'enter' : 'refresh',
  607. sid: this.sid,
  608. nickname: this.userInfo.nickname,
  609. username: this.userInfo.username,
  610. userimg: this.userInfo.userimg,
  611. indate: Math.round(new Date().getTime() / 1000),
  612. }, (res) => {
  613. this.synchUsers = res.status === 1 ? res.message : [];
  614. let tmpNum = this.synergyNum;
  615. setTimeout(() => {
  616. if (tmpNum === this.synergyNum) {
  617. this.synergyNum++;
  618. this.synergy();
  619. }
  620. }, 10000);
  621. });
  622. }
  623. }
  624. },
  625. refreshSid() {
  626. this.sid = this.$route.params.sid;
  627. if (typeof this.$route.params.other === "object") {
  628. this.$set(this.docDetail, 'title', $A.getObject(this.$route.params.other, 'title'))
  629. }
  630. },
  631. getSid() {
  632. return $A.runNum($A.getMiddle(this.sid, null, '-'));
  633. },
  634. refreshDetail() {
  635. this.docDetail = { };
  636. this.docContent = { };
  637. this.bakContent = null;
  638. this.getDetail();
  639. },
  640. getDetail() {
  641. this.loadIng++;
  642. $A.apiAjax({
  643. url: 'docs/section/content',
  644. data: {
  645. act: 'edit',
  646. id: this.sid,
  647. },
  648. complete: () => {
  649. this.loadIng--;
  650. },
  651. error: () => {
  652. this.goBackDirect();
  653. alert(this.$L('网络繁忙,请稍后再试!'));
  654. },
  655. success: (res) => {
  656. if (res.ret === 1) {
  657. this.docDetail = res.data;
  658. this.docContent = $A.jsonParse(res.data.content);
  659. this.bakContent = this.hid == 0 ? $A.jsonStringify(this.docContent) : '';
  660. this.continueLock(1000);
  661. } else {
  662. this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
  663. }
  664. }
  665. });
  666. },
  667. handleSection(act, detail) {
  668. switch (act) {
  669. case 'open':
  670. this.handleSection('openBefore', {sid: detail.id, other: detail || {}})
  671. break;
  672. case 'openBefore':
  673. if (!this.equalContent) {
  674. this.$Modal.confirm({
  675. title: this.$L('温馨提示'),
  676. content: this.$L('是否放弃保存修改的内容?'),
  677. cancelText: this.$L('取消'),
  678. okText: this.$L('放弃保存'),
  679. onOk: () => {
  680. this.handleSection('openConfirm', detail)
  681. }
  682. });
  683. } else {
  684. this.handleSection('openConfirm', detail)
  685. }
  686. break;
  687. case 'openConfirm':
  688. this.goForward({name: 'docs-edit', params: detail}, true);
  689. this.refreshSid();
  690. this.docDrawerShow = false;
  691. break;
  692. }
  693. },
  694. handleSynch(username) {
  695. if (username == this.userInfo.username) {
  696. return;
  697. }
  698. if (typeof window.onChatOpenUserName === "function") {
  699. window.onChatOpenUserName(username);
  700. }
  701. },
  702. handleClick(act) {
  703. switch (act) {
  704. case "back":
  705. if (this.equalContent) {
  706. this.goBackDirect();
  707. return;
  708. }
  709. this.$Modal.confirm({
  710. title: this.$L('温馨提示'),
  711. content: this.$L('是否放弃修改的内容返回?'),
  712. cancelText: this.$L('放弃保存'),
  713. onCancel: () => {
  714. this.goBackDirect();
  715. },
  716. okText: this.$L('保存并返回'),
  717. onOk: () => {
  718. this.handleClick('save');
  719. this.goBackDirect();
  720. }
  721. });
  722. break;
  723. case "save":
  724. this.bakContent = $A.jsonStringify(this.docContent);
  725. $A.apiAjax({
  726. url: 'docs/section/save',
  727. method: 'post',
  728. data: Object.assign(this.docDetail, {
  729. id: this.getSid(),
  730. content: this.bakContent
  731. }),
  732. error: () => {
  733. this.bakContent = '';
  734. alert(this.$L('网络繁忙,保存失败!'));
  735. },
  736. success: (res) => {
  737. if (res.ret === 1) {
  738. this.$Message.success(res.msg);
  739. this.historyNoDataText = '';
  740. if (this.hid != 0) {
  741. this.hid = 0;
  742. this.goForward({name: 'docs-edit', params: {sid: this.getSid()}}, true);
  743. }
  744. } else {
  745. this.bakContent = '';
  746. this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
  747. }
  748. }
  749. });
  750. break;
  751. case "menu":
  752. case "history":
  753. this.docDrawerTab = act;
  754. this.docDrawerShow = true
  755. break;
  756. case "share":
  757. this.$Modal.confirm({
  758. render: (h) => {
  759. return h('div', [
  760. h('div', {
  761. style: {
  762. fontSize: '16px',
  763. fontWeight: '500',
  764. marginBottom: '20px',
  765. }
  766. }, this.$L('文档链接')),
  767. h('Input', {
  768. props: {
  769. value: this.handleClick('view'),
  770. readonly: true,
  771. },
  772. })
  773. ])
  774. },
  775. });
  776. break;
  777. case "lock":
  778. case "unlock":
  779. $A.apiAjax({
  780. url: 'docs/section/lock?id=' + this.getSid(),
  781. data: {
  782. act: act,
  783. },
  784. error: () => {
  785. alert(this.$L('网络繁忙,请稍后再试!'));
  786. },
  787. success: (res) => {
  788. if (res.ret === 1) {
  789. if (this.docDetail.lockname != res.data.lockname) {
  790. this.$Message.success(res.msg);
  791. }
  792. this.$set(this.docDetail, 'lockname', res.data.lockname);
  793. this.$set(this.docDetail, 'lockdate', res.data.lockdate);
  794. this.continueLock(20000);
  795. } else {
  796. this.$Modal.error({title: this.$L('温馨提示'), content: res.msg});
  797. }
  798. }
  799. });
  800. break;
  801. case "view":
  802. return $A.webUrl('docs/view/' + this.docDetail.id);
  803. }
  804. },
  805. continueLock(time) {
  806. if (!this.isLock) {
  807. return;
  808. }
  809. if (this.docDetail.lockname != this.userInfo.username) {
  810. return;
  811. }
  812. this.__continueLock = $A.randomString(6);
  813. let tempString = this.__continueLock;
  814. setTimeout(() => {
  815. if (tempString != this.__continueLock) {
  816. return;
  817. }
  818. if (!this.isLock) {
  819. return;
  820. }
  821. if (this.docDetail.lockname != this.userInfo.username) {
  822. return;
  823. }
  824. this.handleClick('lock');
  825. }, time);
  826. },
  827. exportMenu(act) {
  828. switch (this.docDetail.type) {
  829. case 'mind':
  830. this.$refs.myMind.exportHandle(act == 'pdf' ? 1 : 0, this.docDetail.title);
  831. break;
  832. case 'flow':
  833. this.$refs.myFlow[act == 'pdf' ? 'exportPDF' : 'exportPNG'](this.docDetail.title, 1);
  834. break;
  835. case 'sheet':
  836. this.$refs.mySheet.exportExcel(this.docDetail.title, act);
  837. break;
  838. }
  839. }
  840. },
  841. }
  842. </script>