edit.vue 38 KB

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