km-knowledge-map.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. <template>
  2. <div :class="$style.wrapHeight">
  3. <div :class="$style.rowHeight">
  4. <km-tree-async
  5. ref="tree"
  6. :load-tree-data="loadTreeData"
  7. option-count="count"
  8. @treeSelectd="treeSelectd"
  9. />
  10. <div :class="$style.rightcard">
  11. <sd-detail-modal
  12. ref="kMapDetail"
  13. :record-id="kMapid"
  14. page-id="kmap/kmKmap/kmKmapData"
  15. :modal-props="{ width: 1000 }"
  16. @saved="fnKMapSaved"
  17. @actionBtnClick="actionBtnClick"
  18. >
  19. <template v-slot="{ model, fields }">
  20. <km-kmap-table
  21. ref="kmapTable"
  22. :model="model"
  23. :fields="fields"
  24. :default-category="defaultCategory"
  25. />
  26. </template>
  27. </sd-detail-modal>
  28. <a-card>
  29. <a-tabs v-model="activeKey">
  30. <a-tab-pane key="picturecard" tab="图文">
  31. <div :class="$style.wrapper">
  32. <div :class="$style.header">
  33. <div :class="$style.order">
  34. 排序:<span
  35. :class="[orderType === 'creationTime' ? $style.active : '']"
  36. @click="fnSetOrderType('creationTime')"
  37. >
  38. 发布时间<a-icon v-if="creationTimeDesc" type="caret-down" /><a-icon
  39. v-else
  40. type="caret-up"
  41. />
  42. </span>
  43. |<span
  44. :class="[orderType === 'readTimes' ? $style.active : '']"
  45. @click="fnSetOrderType('readTimes')"
  46. >
  47. 浏览次数
  48. </span>
  49. </div>
  50. <a-input-search
  51. placeholder="请输入搜索条件"
  52. allow-clear
  53. @search="onSearchChange"
  54. />
  55. <a-button
  56. v-if="showDeleteBtn"
  57. :disabled="pictureRowSelection.length <= 0"
  58. @click="deleteRows"
  59. >
  60. 删除
  61. </a-button>
  62. <a-button v-if="showCreateBtn" type="primary" @click="fnCreatDoc">
  63. 新建
  64. </a-button>
  65. </div>
  66. <a-list
  67. :grid="{ gutter: 16, column: 4 }"
  68. :data-source="pictureData"
  69. :pagination="pagination"
  70. :loading="loading"
  71. type="flex"
  72. >
  73. <a-list-item slot="renderItem" slot-scope="item">
  74. <a-card :class="$style.picturecard">
  75. <div slot="cover" :class="$style.picturecover">
  76. <img
  77. v-if="item.cover"
  78. :class="$style.img"
  79. :src="
  80. (`api/flow-mobile/v1/task-form-process/download-attachments/` +
  81. item.cover)
  82. | sdResource
  83. "
  84. class="ant-upload-list-item-image"
  85. @click="fnReadDoc(item)"
  86. />
  87. </div>
  88. <a-card-meta>
  89. <template slot="title">
  90. <a-checkbox
  91. v-if="showDeleteBtn"
  92. :value="item.id"
  93. :checked="pictureRowSelection.includes(item.id)"
  94. @change="fnPictureSelect"
  95. >
  96. </a-checkbox>
  97. <span :class="{ [$style.title]: showDeleteBtn }">
  98. <a @click="fnReadDoc(item)">{{ item.kmapName }}</a>
  99. </span>
  100. </template>
  101. <template slot="description">
  102. <div>
  103. <span :class="$style.user">{{ item.creatorName }}</span>
  104. <span :class="$style.datatime">{{
  105. item.creationTime | sdDateFormat('YYYY-MM-DD')
  106. }}</span>
  107. <span><a-icon type="sd-eye" />{{ item.readTimes }}</span>
  108. <span v-if="showEditBtn" :class="$style.edit">
  109. <a @click="fnEditDoc(item)">编辑</a>
  110. </span>
  111. </div>
  112. </template>
  113. </a-card-meta>
  114. </a-card>
  115. </a-list-item>
  116. </a-list>
  117. </div>
  118. </a-tab-pane>
  119. <a-tab-pane key="textlist" tab="列表">
  120. <sd-oa-table
  121. v-if="expressions.length > 0"
  122. ref="kMapTable"
  123. :form-id="formId"
  124. page-id="kmap/kmKmap/kmKmapData"
  125. :columns="columns"
  126. :actions="showEditBtn === true ? actions : actions.slice(0, 2)"
  127. :filter-expressions="expressions"
  128. :show-selection="showDeleteBtn"
  129. :modal-props="{ width: 1000 }"
  130. :search-fields="['kmapName']"
  131. @recordsDeleted="onRecordsDeleted"
  132. >
  133. <a slot="fldSubject" slot-scope="text, record" @click="fnReadDoc(record)">
  134. {{ text }}
  135. </a>
  136. </sd-oa-table>
  137. </a-tab-pane>
  138. </a-tabs>
  139. </a-card>
  140. </div>
  141. </div>
  142. </div>
  143. </template>
  144. <script>
  145. import { Message, Modal } from 'ant-design-vue'
  146. import { getUserPerms } from '@/common/store-mixin'
  147. import crossWindowWatcher from '@/common/services/cross-window-watcher'
  148. import PageService from '@/common/services/page-service'
  149. import TableActionTypes from '@/common/services/table-action-types'
  150. import TableColumnTypes from '@/common/services/table-column-types'
  151. import KmKnowledageService from '../km-knowledage-service'
  152. import components from './_import-components/km-knowledge-map-import'
  153. export default {
  154. name: 'KmKnowledgeMap',
  155. metaInfo: {
  156. title: '知识地图',
  157. },
  158. components,
  159. provide() {
  160. return {
  161. oaKmapContext: this,
  162. }
  163. },
  164. data() {
  165. return {
  166. activeKey: 'textlist',
  167. expressions: [],
  168. columns: [
  169. {
  170. title: '序号',
  171. customRender: (text, record, index) => `${index + 1}`,
  172. width: '100px',
  173. },
  174. {
  175. title: '标题',
  176. dataIndex: 'kmapName',
  177. scopedSlots: { customRender: 'fldSubject' },
  178. },
  179. {
  180. title: '分类',
  181. dataIndex: 'kmapCategoryName',
  182. },
  183. {
  184. title: '作者',
  185. dataIndex: 'creatorName',
  186. },
  187. {
  188. title: '阅读次数',
  189. dataIndex: 'readTimes',
  190. },
  191. {
  192. title: '发布时间',
  193. dataIndex: 'creationTime',
  194. sdRender: TableColumnTypes.date,
  195. defaultSortOrder: 'desc',
  196. sorter: true,
  197. },
  198. ],
  199. actions: [
  200. {
  201. label: '新建',
  202. id: 'create',
  203. type: TableActionTypes.primary,
  204. permission: 'create',
  205. callback: () => {
  206. this.fnCreatDoc()
  207. },
  208. },
  209. {
  210. label: '删除',
  211. id: 'delete',
  212. type: TableActionTypes.oa.delete, // 删除按钮,不需要回调,会自动处理
  213. },
  214. {
  215. label: '编辑',
  216. id: 'edit',
  217. type: TableActionTypes.inline,
  218. callback: (record) => {
  219. this.fnEditDoc(record)
  220. },
  221. },
  222. ],
  223. formId: 'kmKmapData',
  224. showEditBtn: false,
  225. // 图文列表参数
  226. showCreateBtn: false,
  227. showDeleteBtn: false,
  228. pictureData: [],
  229. pagination: {
  230. onChange: (page) => {
  231. this.paginationChange(page)
  232. },
  233. current: 1,
  234. pageSize: 8,
  235. showTotal(total) {
  236. return `共${total}条`
  237. },
  238. },
  239. loading: false, // 图文列表数据的loading
  240. kMapid: null,
  241. pictureExpressions: [],
  242. orderType: 'creationTime',
  243. creationTimeDesc: true,
  244. pictureRowSelection: [],
  245. searchText: '',
  246. defaultCategory: '',
  247. }
  248. },
  249. watch: {
  250. pictureExpressions() {
  251. this.pictureListRefresh(true)
  252. },
  253. orderType() {
  254. this.pictureListRefresh()
  255. },
  256. creationTimeDesc() {
  257. this.pictureListRefresh()
  258. },
  259. },
  260. created() {
  261. this.loadData()
  262. // 判断权限
  263. const userPerms = getUserPerms()
  264. if ('kmKmapData-create' in userPerms) {
  265. this.showCreateBtn = true
  266. }
  267. if ('kmKmapData-delete' in userPerms) {
  268. this.showDeleteBtn = true
  269. }
  270. if ('kmKmapData-update' in userPerms) {
  271. this.showEditBtn = true
  272. }
  273. },
  274. methods: {
  275. // 获取分类树
  276. loadTreeData(parentCatId) {
  277. const params = {
  278. pageId: 'KmKmapData',
  279. categoryId: parentCatId || 0,
  280. }
  281. return KmKnowledageService.getKmapTree(params).then((res) => {
  282. return res.data
  283. })
  284. },
  285. // 查看知识地图
  286. fnReadDoc(record) {
  287. const url = `/km-kmap-pages/` + record.id
  288. crossWindowWatcher.waitForChanged(url).then((refreshFlag) => {
  289. if (refreshFlag) {
  290. this.$refs.kMapTable.refresh()
  291. this.pictureListRefresh()
  292. }
  293. })
  294. },
  295. // 创建知识地图
  296. fnCreatDoc() {
  297. this.kMapid = null
  298. this.$refs.kMapDetail.show()
  299. },
  300. fnEditDoc(record) {
  301. this.kMapid = record.id
  302. this.$refs.kMapDetail.show()
  303. },
  304. actionBtnClick(evt, btn) {
  305. if (btn.buttonId === 'save') {
  306. evt.waitUntil(
  307. new Promise((resolve, reject) => {
  308. if (this.$refs.kMapDetail.getFieldValue('type') === '0') {
  309. if (this.$refs.kMapDetail.getFieldValue('kmKmapKnowledgeList')) {
  310. resolve()
  311. } else {
  312. Message.warn('不使用模板时请至少录入一条关联知识')
  313. evt.preventDefault()
  314. resolve()
  315. }
  316. } else {
  317. resolve()
  318. }
  319. })
  320. )
  321. }
  322. },
  323. // 知识地图保存
  324. fnKMapSaved() {
  325. this.$refs.kMapTable.refresh()
  326. this.pictureListRefresh()
  327. },
  328. // 树选择节点后获取列表数据
  329. treeSelectd(item) {
  330. let parentId = ''
  331. let parentName = ''
  332. if (item.id !== undefined) {
  333. parentId = item.id
  334. parentName = item.text
  335. // 走这里表示是根节点,根节点要是没有的话就不用向上找了
  336. } else {
  337. parentId = item.selectedNodes[0].data.props.id
  338. parentName = item.selectedNodes[0].data.props.text
  339. }
  340. const obj = {
  341. id: parentId,
  342. name: parentName,
  343. }
  344. this.defaultCategory = [obj]
  345. this.selectdParentId = parseInt(parentId)
  346. this.selectdParentName = parentName
  347. const filter = [
  348. {
  349. dataType: 'str',
  350. name: 'kmapCategoryId',
  351. op: 'eq',
  352. stringValue: this.selectdParentId,
  353. },
  354. ]
  355. this.pictureExpressions = filter
  356. this.expressions = filter
  357. },
  358. // 图片列表页面翻页
  359. paginationChange(page) {
  360. this.pagination.current = page
  361. this.loadData()
  362. },
  363. pictureListRefresh(toFirstPage) {
  364. if (toFirstPage) this.pagination.current = 1
  365. return this.loadData()
  366. },
  367. loadData() {
  368. const pagination = this.pagination
  369. this.loading = true
  370. const param = {
  371. columns: 'kmapName,creationTime,cover,kmapCategoryName,creatorName,readTimes',
  372. maxResults: pagination.pageSize,
  373. startPosition: pagination.pageSize * (pagination.current - 1),
  374. formId: this.formId,
  375. }
  376. let orderBy = ''
  377. if (this.orderType === 'creationTime') {
  378. if (this.creationTimeDesc) {
  379. orderBy = 'creationTime desc'
  380. } else {
  381. orderBy = 'creationTime asc'
  382. }
  383. } else {
  384. orderBy = 'readTimes desc'
  385. }
  386. param.orderBy = orderBy
  387. if (this.searchText) {
  388. const searchExpressions = [
  389. {
  390. dataType: 'exps',
  391. op: 'or',
  392. expressionsValue: [
  393. {
  394. dataType: 'str',
  395. name: 'kmapName',
  396. op: 'like',
  397. stringValue: `%${this.searchText}%`,
  398. },
  399. ],
  400. },
  401. ]
  402. param.expressions = [...searchExpressions, ...this.pictureExpressions]
  403. } else {
  404. param.expressions = this.pictureExpressions
  405. }
  406. PageService.getList(param).then((res) => {
  407. this.pagination.total = res.data.totalSize
  408. this.pictureData = res.data.data
  409. this.loading = false
  410. const newInfo = { ...this.pagination }
  411. newInfo.total = res.data.totalSize
  412. this.pagination = newInfo
  413. })
  414. },
  415. // 处理排序
  416. fnSetOrderType(type) {
  417. if (type === 'creationTime') {
  418. if (this.orderType === 'creationTime') {
  419. this.creationTimeDesc = !this.creationTimeDesc
  420. }
  421. }
  422. this.orderType = type
  423. },
  424. // 图文列表选中
  425. fnPictureSelect(e) {
  426. if (e.target.checked) {
  427. if (this.pictureRowSelection.indexOf(e.target.value) === -1) {
  428. this.pictureRowSelection.push(e.target.value)
  429. }
  430. } else {
  431. this.pictureRowSelection.splice(
  432. this.pictureRowSelection.findIndex((it) => it.value === e.target.value),
  433. 1
  434. )
  435. }
  436. },
  437. // 列表删除数据时图文也刷新一下
  438. onRecordsDeleted() {
  439. this.pictureListRefresh()
  440. this.$refs.tree.refresh() // 刷新树
  441. },
  442. // 图文列表删除数据
  443. deleteRows() {
  444. Modal.confirm({
  445. title: '你确定删除这项内容吗?',
  446. content: '删除这条数据后,就无法恢复初始的状态。',
  447. okText: '删除',
  448. okType: 'danger',
  449. onOk: () => {
  450. this.loading = true
  451. const params = {
  452. ids: this.pictureRowSelection.join(','),
  453. }
  454. PageService.delete(params, this.formId).then((res) => {
  455. if (res.status === 200) {
  456. this.pictureRowSelection = []
  457. this.loading = false
  458. this.pictureListRefresh()
  459. this.$refs.kMapTable.refresh()
  460. }
  461. })
  462. },
  463. })
  464. },
  465. onSearchChange(text) {
  466. if (this.searchText === text) return
  467. this.searchText = text.trim()
  468. const pagination = this.pagination
  469. pagination.current = 1
  470. this.localPagination = { ...pagination }
  471. this.loadData()
  472. },
  473. },
  474. }
  475. </script>
  476. <style module lang="scss">
  477. @use '@/common/design' as *;
  478. .wrap-height {
  479. height: 100%;
  480. .row-height {
  481. display: flex;
  482. flex: auto;
  483. height: 100%;
  484. .rightcard {
  485. flex: 1;
  486. width: calc(100% - 20%);
  487. height: 100%;
  488. }
  489. }
  490. }
  491. // 图文搜索框
  492. .wrapper {
  493. :global(.ant-input-search) {
  494. width: 200px;
  495. }
  496. :global(.ant-btn) {
  497. margin: 5px;
  498. }
  499. :global(.ant-list) {
  500. margin-top: 20px;
  501. }
  502. margin-top: -64px;
  503. .header {
  504. position: relative;
  505. z-index: 1;
  506. width: 80%;
  507. height: 42px;
  508. margin: 3px 0 3px 20%;
  509. text-align: right;
  510. .order {
  511. display: inline-block;
  512. margin-right: 30px;
  513. span {
  514. margin: 0 10px;
  515. cursor: pointer;
  516. }
  517. .active {
  518. color: $primary-color;
  519. }
  520. }
  521. }
  522. }
  523. // 图文样式
  524. .picturecard {
  525. border: 1px solid $border-color-split;
  526. .picturecover {
  527. height: 18vh;
  528. background-image: url('../images/noimage.png');
  529. background-repeat: no-repeat;
  530. background-position-x: center;
  531. background-position-y: center;
  532. img[src=''],
  533. img:not([src]) {
  534. opacity: 0;
  535. }
  536. .img {
  537. width: 100%;
  538. height: 100%;
  539. border: none;
  540. }
  541. }
  542. .title {
  543. padding-left: 12px;
  544. }
  545. .datatime {
  546. padding: 0 10px;
  547. }
  548. .edit {
  549. float: right;
  550. }
  551. }
  552. </style>