飞天云平台-国产化
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

682 lines
26 KiB

6 months ago
  1. <template>
  2. <div class="app-container">
  3. <div class="venue-header">
  4. <h4><i class="iconfont icon-shujia" />书架列表</h4>
  5. <p><i class="iconfont icon-gongsi" />{{ user.fonds.fondsName }}</p>
  6. </div>
  7. <div class="venue-content">
  8. <div class="venue-left">
  9. <div class="head-container">
  10. <div class="head-search">
  11. <!-- 搜索 -->
  12. <el-select v-model="selectFloorVal" size="small" placeholder="楼层" class="filter-item" style="width: 80px" value-key="id" @change="changeBeforeFloor">
  13. <el-option v-for="(item,index) in floorOptions" :key="index" :label="item.floorName" :value="item" />
  14. </el-select>
  15. <el-select v-model="selectRegionVal" size="small" placeholder="区域" class="filter-item" style="width: 140px" value-key="id" @change="changeBeforeRegion">
  16. <el-option v-for="(item,index) in regionOptions" :key="index" :label="item.regionName" :value="item" />
  17. </el-select>
  18. <!-- <el-input v-model="query.search" clearable size="small" placeholder="输入关键字搜索" prefix-icon="el-icon-search" style="width: 200px;" class="filter-item" @clear="crud.toQuery" @keyup.enter.native="crud.toQuery" /> -->
  19. <!-- <rrOperation /> -->
  20. </div>
  21. <crudOperation :permission="permission">
  22. <template v-slot:middle>
  23. <el-button slot="reference" size="mini" :loading="crud.delAllLoading" :disabled="crud.selections.length === 0" @click="toDelete(crud.selections)">
  24. <i class="iconfont icon-shanchu" />
  25. 删除
  26. </el-button>
  27. </template>
  28. </crudOperation>
  29. </div>
  30. <div>
  31. <div class="double-click-btn"><i class="iconfont icon-zhuyi-lan" /><span>双击列表数据查看对应架位</span></div>
  32. <el-table
  33. ref="table"
  34. v-loading="crud.loading"
  35. :data="crud.data"
  36. style="width: 100%;"
  37. height="507"
  38. @selection-change="selectionChangeHandler"
  39. @row-dblclick="onRowDblclick"
  40. @row-click="clickRowHandler"
  41. >
  42. <el-table-column type="selection" align="center" width="55" />
  43. <!-- <el-table-column type="index" label="排序" /> -->
  44. <el-table-column prop="shelfName" label="书架名称" />
  45. <el-table-column prop="shelfShelf" label="书架规格">
  46. <template slot-scope="scope">
  47. <span>{{ scope.row.shelfFloor + ' X ' + scope.row.shelfShelf }}</span>
  48. </template>
  49. </el-table-column>
  50. <el-table-column prop="rowType" label="单/双面">
  51. <template slot-scope="scope">
  52. <span>{{ scope.row.rowType === 1 ? '单面' :'双面' }}</span>
  53. </template>
  54. </el-table-column>
  55. <el-table-column prop="floorName" label="所属楼层" />
  56. <el-table-column prop="regionName" label="所属区域" min-width="100" />
  57. <el-table-column prop="signPoint" label="标注">
  58. <template slot-scope="scope">
  59. <span :class="['row-state', scope.row.signPoint ? 'end-state' : 'cancel-state' ]">{{ scope.row.signPoint ? '已标注': '未标注' }}</span>
  60. </template>
  61. </el-table-column>
  62. </el-table>
  63. <!--分页组件-->
  64. <pagination v-if="crud.data.length!==0" />
  65. </div>
  66. </div>
  67. <div class="venue-right">
  68. <div class="container-right tab-content">
  69. <span class="right-top-line" />
  70. <span class="left-bottom-line" />
  71. <ul class="tab-nav">
  72. <li class="active-tab-nav">区域书架<i /></li>
  73. <!-- 最右侧装饰img -->
  74. <span class="tab-right-img" />
  75. <el-button size="mini" class="venue-mark" :disabled="crud.selections.length !== 1" @click="handleMark">
  76. <i class="el-icon-edit" />
  77. 书架标注
  78. </el-button>
  79. </ul>
  80. <div class="venue-preview">
  81. <!-- <img :src="imageUrl" :onerror="defaultImg" alt=""> -->
  82. <div v-show="currentMarkData && currentMarkData.signPoint">
  83. <canvas id="canvasPreview" :width="width" :height="height" />
  84. </div>
  85. <img v-if="currentMarkData && !currentMarkData.signPoint" :src="imageUrl" :onerror="defaultImg" alt="">
  86. <img v-if="!currentMarkData" :src="imageUrl" :onerror="defaultImg" alt="">
  87. </div>
  88. </div>
  89. </div>
  90. </div>
  91. <!-- form -->
  92. <el-dialog append-to-body :close-on-click-modal="false" :modal-append-to-body="false" :before-close="crud.cancelCU" :visible="crud.status.cu > 0" :title="crud.status.title">
  93. <span class="dialog-right-top" />
  94. <span class="dialog-left-bottom" />
  95. <div class="setting-dialog">
  96. <el-form ref="form" :rules="rules" :model="form" inline size="small" label-width="90px">
  97. <el-form-item label="所属楼层" prop="floorName">
  98. <el-input v-model="form.floorName" disabled />
  99. </el-form-item>
  100. <el-form-item label="所属区域" prop="regionName">
  101. <el-input v-model="form.regionName" disabled />
  102. </el-form-item>
  103. <el-row>
  104. <el-form-item label="单/双排" prop="rowType">
  105. <el-radio-group v-model="form.rowType" v-removeAriaHidden size="mini">
  106. <el-radio :label="1">单排</el-radio>
  107. <el-radio :label="2">双排</el-radio>
  108. </el-radio-group>
  109. </el-form-item>
  110. <el-form-item v-if="form.rowType===1" label="A/B面" prop="toward">
  111. <el-select v-model="form.toward" placeholder="请选择" style="width: 225px;">
  112. <el-option
  113. v-for="(item,index) in abOptions"
  114. :key="index"
  115. :label="item.name"
  116. :value="item.value"
  117. />
  118. </el-select>
  119. </el-form-item>
  120. </el-row>
  121. <el-row>
  122. <el-form-item label="书架排号" prop="shelfRow">
  123. <el-input v-model="form.shelfRow" @blur="formatShelfRow" />
  124. </el-form-item>
  125. <el-form-item label="书架名称" prop="shelfName">
  126. <el-input v-model="computedShelfName" disabled />
  127. </el-form-item>
  128. </el-row>
  129. <el-form-item label="书架规格" prop="rackSpecs">
  130. <el-input-number v-model.number="form.shelfFloor" :min="1" :max="999" controls-position="right" style="width:80px;" />
  131. <span style="font-size: 12px;"></span>
  132. <span style="padding:0 2px;"></span>
  133. <el-input-number v-model.number="form.shelfShelf" :min="1" :max="999" controls-position="right" style="width: 80px;" />
  134. <span style="font-size: 12px;"></span>
  135. </el-form-item>
  136. <el-form-item label="架起始标" prop="startShelf">
  137. <el-input-number v-model.number="form.startShelf" :min="1" :max="999" controls-position="right" />
  138. </el-form-item>
  139. <el-row>
  140. <el-form-item label="架号顺序" prop="shelfType">
  141. <el-select v-model="form.shelfType" placeholder="请选择" style="width: 586px;">
  142. <el-option
  143. v-for="(item,index) in rackOrderOptions"
  144. :key="index"
  145. :label="item.name"
  146. :value="item.key"
  147. />
  148. </el-select>
  149. </el-form-item>
  150. </el-row>
  151. <el-row>
  152. <el-form-item label="层号顺序" prop="floorType">
  153. <el-select v-model="form.floorType" placeholder="请选择" style="width: 586px;">
  154. <el-option
  155. v-for="(item,index) in layerSeqOptions"
  156. :key="index"
  157. :label="item.name"
  158. :value="item.key"
  159. />
  160. </el-select>
  161. </el-form-item>
  162. </el-row>
  163. <el-form-item label="倒架规则" prop="shelfRule">
  164. <el-radio-group v-model="form.shelfRule" v-removeAriaHidden size="mini">
  165. <el-radio :label="1">有序</el-radio>
  166. <el-radio :label="2">无序</el-radio>
  167. </el-radio-group>
  168. </el-form-item>
  169. <el-form-item label="错架判断" prop="shelfErrorJudge">
  170. <el-radio-group v-model="form.shelfErrorJudge" v-removeAriaHidden size="mini">
  171. <el-radio :label="2">格子</el-radio>
  172. <el-radio :label="1">书架</el-radio>
  173. </el-radio-group>
  174. </el-form-item>
  175. </el-form>
  176. <div slot="footer" class="dialog-footer">
  177. <el-button type="text" @click="crud.cancelCU">取消</el-button>
  178. <el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">保存</el-button>
  179. </div>
  180. </div>
  181. </el-dialog>
  182. <!-- 标注 -->
  183. <el-dialog class="mark-dialog" :close-on-click-modal="false" :append-to-body="true" :title="titleMark" :visible.sync="markVisible" :before-close="handleCloseDialog">
  184. <span class="dialog-right-top" />
  185. <span class="dialog-left-bottom" />
  186. <div class="setting-dialog">
  187. <MarkCover ref="markRefs" :is-book-shelf="true" :current-mark-data="currentMarkData" :image-url="imageUrl" @handleCloseDialog="handleCloseDialog" />
  188. </div>
  189. </el-dialog>
  190. </div>
  191. </template>
  192. <script>
  193. import { FetchLibraryFloorListAll } from '@/api/floor/index'
  194. import { FetchInitLibraryRegionList } from '@/api/area/index'
  195. import crudShelf from '@/api/shelf/index'
  196. import CRUD, { presenter, header, form, crud } from '@crud/crud'
  197. import crudOperation from '@crud/CRUD.operation'
  198. import pagination from '@crud/Pagination'
  199. import { mapGetters } from 'vuex'
  200. import defaultImg from '@/assets/images/system/default-img.jpg'
  201. import MarkCover from '@/views/components/mark.vue'
  202. import { fabric } from 'fabric'
  203. const defaultForm = { id: null, floorName: null, floorId: null, regionName: null, rowType: 1, toward: 1, shelfRow: '', shelfName: '', shelfShelf: null, shelfFloor: null, startShelf: null, shelfType: 1, floorType: 1, shelfRule: 1, shelfErrorJudge: 2, signPoint: '' }
  204. export default {
  205. name: 'Bookshelf',
  206. components: { crudOperation, pagination, MarkCover },
  207. cruds() {
  208. return CRUD({ title: '书架', idField: 'shelfId', url: 'api/bookShelf/initBookShelfList', crudMethod: { ...crudShelf }, sort: [], optShow: {
  209. add: true,
  210. edit: true,
  211. del: false,
  212. download: false,
  213. group: false,
  214. reset: false
  215. },
  216. queryOnPresenterCreated: false
  217. })
  218. },
  219. mixins: [presenter(), header(), form(defaultForm), crud()],
  220. data() {
  221. return {
  222. permission: {
  223. add: ['admin', 'floor:add'],
  224. edit: ['admin', 'floor:edit'],
  225. del: ['admin', 'floor:del']
  226. },
  227. floorOptions: [],
  228. regionOptions: [],
  229. selectFloorVal: null,
  230. selectRegionVal: null,
  231. abOptions: [
  232. { value: 1, name: 'A面' },
  233. { value: 2, name: 'B面' }
  234. ],
  235. rackOrderOptions: [
  236. { key: 1, name: '始终最左边为第1架(S型排架)' },
  237. { key: 2, name: 'A面最左为第1架(B面最左为最后1架)' },
  238. { key: 3, name: 'B面最左为第1架(A面最左为最后1架)' }
  239. ],
  240. layerSeqOptions: [
  241. { key: 1, name: '最顶层为第一层(从上至下)' },
  242. { key: 2, name: '最底层为第一层(从下至上)' }
  243. ],
  244. rules: {
  245. floorName: [
  246. { required: true, message: '所属楼层不可为空', trigger: 'blur' }
  247. ],
  248. regionName: [
  249. { required: true, message: '所属区域不可为空', trigger: 'blur' }
  250. ],
  251. rowType: [
  252. { required: true, message: '请选择单双排', trigger: 'change' }
  253. ],
  254. shelfRow: [
  255. { required: true, message: '书架排号不可为空', trigger: 'blur' }
  256. ],
  257. shelfName: [
  258. { validator: this.validateShelfName, trigger: 'blur' }
  259. ],
  260. rackSpecs: [
  261. { validator: this.validateRackSpecs, trigger: 'blur' }
  262. ],
  263. startShelf: [
  264. { required: true, message: '架起始标不可为空', trigger: 'blur' }
  265. ],
  266. shelfType: [
  267. { required: true, message: '请选择架号顺序', trigger: 'change' }
  268. ],
  269. floorType: [
  270. { required: true, message: '请选择层号顺序', trigger: 'change' }
  271. ],
  272. shelfRule: [
  273. { required: true, message: '请选择倒架规则', trigger: 'change' }
  274. ],
  275. shelfErrorJudge: [
  276. { required: true, message: '请选择错架判断', trigger: 'change' }
  277. ]
  278. },
  279. defaultImg: defaultImg,
  280. imageUrl: defaultImg,
  281. markVisible: false, // 区域标注
  282. titleMark: '书架标注',
  283. currentMarkData: null,
  284. canvasPreview: {},
  285. width: 900,
  286. height: 600,
  287. drawWidth: 2 // 笔触宽度
  288. }
  289. },
  290. computed: {
  291. ...mapGetters([
  292. 'user',
  293. 'baseApi'
  294. ]),
  295. computedShelfName() {
  296. const { shelfRow, rowType, toward } = this.form
  297. if (!shelfRow) {
  298. return ''
  299. }
  300. const baseName = `${shelfRow}`
  301. if (rowType === 1 && toward !== null) {
  302. return `${baseName}${this.abOptions.find(option => option.value === toward).name}`
  303. } else if (rowType === 2) {
  304. return baseName
  305. }
  306. return ''
  307. }
  308. },
  309. watch: {
  310. computedShelfName(newVal) {
  311. this.form.shelfName = newVal
  312. },
  313. width() {
  314. this.canvasPreview.setWidth(this.width)
  315. },
  316. height() {
  317. this.canvasPreview.setHeight(this.height)
  318. }
  319. },
  320. beforeDestroy() {
  321. window.removeEventListener('beforeunload', this.clearLocalStorage)
  322. },
  323. created() {
  324. this.getLibraryFloorListAll()
  325. },
  326. mounted() {
  327. },
  328. methods: {
  329. clearLocalStorage() {
  330. const key = 'formArea'
  331. if (localStorage.getItem(key)) {
  332. localStorage.removeItem(key)
  333. }
  334. },
  335. formatShelfRow() {
  336. let value = this.form.shelfRow
  337. value = value.toString()
  338. if (value.length < 3) {
  339. value = value.padStart(3, '0')
  340. } else if (value.length > 3) {
  341. value = value.slice(0, 3)
  342. }
  343. this.form.shelfRow = value
  344. },
  345. validateShelfName(rule, value, callback) {
  346. if (this.form.shelfRow) {
  347. if (!value) {
  348. callback(new Error('书架名称不能为空'))
  349. } else {
  350. callback()
  351. }
  352. } else {
  353. callback()
  354. }
  355. },
  356. validateRackSpecs(rule, value, callback) {
  357. // 检查 shelfShelf 和 shelfFloor 是否为空
  358. if (!this.form.shelfShelf) {
  359. callback(new Error('请输入书架规格中书架架数'))
  360. } else if (!this.form.shelfFloor) {
  361. callback(new Error('请输入书架规格中书架层数'))
  362. } else {
  363. callback()
  364. }
  365. },
  366. [CRUD.HOOK.beforeRefresh]() {
  367. console.log(this.$route.query)
  368. if (this.$route.query.formArea) {
  369. const formArea = JSON.parse(localStorage.getItem('formArea'))
  370. if (formArea) {
  371. this.selectFloorVal = {
  372. id: formArea.floorId,
  373. floorMap: formArea.floorMap,
  374. floorName: formArea.floorName
  375. }
  376. this.selectRegionVal = formArea
  377. this.crud.query.floorId = this.selectFloorVal.id
  378. this.crud.query.regionId = this.selectRegionVal.id
  379. FetchInitLibraryRegionList({ 'floorId': this.selectFloorVal.id }).then(res => {
  380. this.regionOptions = res.content
  381. }).catch(() => {
  382. })
  383. }
  384. }
  385. },
  386. [CRUD.HOOK.afterRefresh](crud) {
  387. console.log(crud.data)
  388. if (this.selectRegionVal && this.selectRegionVal.regionMap) {
  389. this.imageUrl = this.baseApi + '/api/fileRelevant/getImg?imgType=1&imgId=' + this.selectRegionVal.regionMap
  390. } else {
  391. this.imageUrl = defaultImg
  392. }
  393. },
  394. // 新增与编辑前做的操作
  395. [CRUD.HOOK.afterToCU](crud, form) {
  396. console.log(form)
  397. console.log('crud.query.floorId', crud.query.floorId)
  398. console.log('selectFloorVal', this.selectFloorVal)
  399. console.log('crud.query.regionId', crud.query.regionId)
  400. console.log('selectRegionVal', this.selectRegionVal)
  401. form.floorId = this.selectFloorVal.id
  402. form.floorName = this.selectFloorVal.floorName
  403. form.regionId = this.selectRegionVal.id
  404. form.regionName = this.selectRegionVal.regionName
  405. },
  406. // 编辑前
  407. [CRUD.HOOK.beforeToEdit](crud, form) {
  408. const params = {
  409. 'shelfId': this.crud.selections[0].shelfId
  410. }
  411. crudShelf.FetchBookShelfDetails(params).then(res => {
  412. form.id = res.id
  413. // 单/双排 1 单 2 双
  414. form.rowType = res.rowType
  415. // A/B面 1 A 2 B
  416. form.toward = res.toward
  417. // 书架排号
  418. form.shelfRow = res.shelfRow
  419. // 书架名称
  420. form.shelfName = res.shelfName
  421. // 书架规格 架
  422. form.shelfShelf = res.shelfShelf
  423. // 书架规格 层
  424. form.shelfFloor = res.shelfFloor
  425. // 架起始标
  426. form.startShelf = res.startShelf
  427. // 架号顺序
  428. form.shelfType = res.shelfType
  429. // 层号顺序
  430. form.floorType = res.floorType
  431. // 倒架规则 1 无序 2 有序
  432. form.shelfRule = res.shelfRule
  433. // 错架判断 1 书架 2 格子
  434. form.shelfErrorJudge = res.shelfErrorJudge
  435. }).catch(() => {
  436. })
  437. },
  438. // 提交前的验证
  439. [CRUD.HOOK.afterValidateCU](crud) {
  440. console.log(crud.form)
  441. delete crud.form.floorName
  442. delete crud.form.regionName
  443. return true
  444. },
  445. // 获取楼层数据
  446. getLibraryFloorListAll() {
  447. FetchLibraryFloorListAll().then(res => {
  448. this.floorOptions = res
  449. if (this.floorOptions.length > 0) {
  450. this.selectFloorVal = this.floorOptions[0]
  451. this.crud.query.floorId = this.selectFloorVal.id
  452. if (this.crud.query.floorId) {
  453. this.getInitLibraryRegionList(this.crud.query.floorId)
  454. }
  455. }
  456. }).catch(() => {
  457. })
  458. },
  459. getInitLibraryRegionList(val) {
  460. const params = {
  461. 'floorId': val
  462. }
  463. FetchInitLibraryRegionList(params).then(res => {
  464. this.regionOptions = res.content
  465. if (this.regionOptions.length > 0) {
  466. this.selectRegionVal = this.regionOptions[0]
  467. this.crud.query.regionId = this.selectRegionVal.id
  468. } else {
  469. this.selectRegionVal = null
  470. this.crud.query.regionId = null
  471. }
  472. this.crud.toQuery()
  473. }).catch(() => {
  474. })
  475. },
  476. changeBeforeFloor(val) {
  477. if (this.$route.query.formArea) {
  478. localStorage.removeItem('formArea')
  479. }
  480. if (val) {
  481. this.selectFloorVal = val
  482. this.crud.query.floorId = val.id
  483. this.getInitLibraryRegionList(val.id)
  484. }
  485. },
  486. changeBeforeRegion(val) {
  487. if (this.$route.query.formArea) {
  488. localStorage.removeItem('formArea')
  489. }
  490. if (val) {
  491. this.selectRegionVal = val
  492. this.crud.query.regionId = val.id
  493. this.crud.toQuery()
  494. }
  495. },
  496. selectionChangeHandler(val) {
  497. this.crud.selections = val
  498. // 处理选择项为1且有签名点的情况
  499. if (this.crud.selections.length === 1 && this.crud.selections[0].signPoint) {
  500. this.currentMarkData = val[0]
  501. if (this.canvasPreview.lowerCanvasEl) {
  502. this.canvasPreview.clear()
  503. this.canvasPreview.dispose()
  504. }
  505. try {
  506. const drawinfo = JSON.parse(this.crud.selections[0].signPoint)
  507. this.initCanvasPreview(drawinfo)
  508. } catch (error) {
  509. console.error(error)
  510. this.resetImageUrl()
  511. }
  512. } else {
  513. // 处理选择项大于1或选择项为0的情况
  514. this.currentMarkData = null
  515. this.setImageUrlBasedOnRegionMap()
  516. }
  517. },
  518. setImageUrlBasedOnRegionMap() {
  519. if (this.selectRegionVal && this.selectRegionVal.regionMap) {
  520. this.imageUrl = `${this.baseApi}/api/fileRelevant/getImg?imgType=1&imgId=${this.selectRegionVal.regionMap}`
  521. } else {
  522. this.resetImageUrl()
  523. }
  524. },
  525. resetImageUrl() {
  526. this.imageUrl = this.defaultImg
  527. },
  528. async handleMark() {
  529. if (this.crud.selections.length === 1) {
  530. const selection = this.crud.selections[0]
  531. if (selection && this.selectRegionVal.regionMap) {
  532. this.markVisible = true
  533. this.currentMarkData = selection
  534. this.titleMark = this.currentMarkData.shelfName + ' - 书架标注'
  535. this.$nextTick(() => {
  536. this.$refs.markRefs.drawinfo = this.currentMarkData && this.currentMarkData.signPoint ? JSON.parse(this.currentMarkData.signPoint) : null
  537. this.$refs.markRefs.initCanvas()
  538. })
  539. } else {
  540. this.$message({ message: '请先上传当前区域图', type: 'error', offset: 8 })
  541. }
  542. } else {
  543. console.error('666')
  544. }
  545. },
  546. clickRowHandler(row) {
  547. this.$refs.table.clearSelection()
  548. this.$refs.table.toggleRowSelection(row)
  549. },
  550. onRowDblclick(row) {
  551. crudShelf.FetchBookShelfDetails({ 'shelfId': row.shelfId }).then(res => {
  552. this.$router.push({ path: '/bookshelf/bookshelfPosition', query: { 'floorName': row.floorName, 'regionName': row.regionName }})
  553. localStorage.setItem('bookShelfDetails', JSON.stringify(res))
  554. }).catch(() => {
  555. })
  556. },
  557. toDelete(datas) {
  558. this.$confirm('此操作将删除当前所选书架<span>你是否还要继续?</span>', '提示', {
  559. confirmButtonText: '继续',
  560. cancelButtonText: '取消',
  561. type: 'warning',
  562. dangerouslyUseHTMLString: true
  563. }).then(() => {
  564. this.crud.delAllLoading = true
  565. const ids = []
  566. datas.forEach(val => {
  567. ids.push(val.shelfId)
  568. })
  569. console.log(ids)
  570. crudShelf.del(ids).then(res => {
  571. console.log(res)
  572. this.$message({ message: res, type: 'success', offset: 8 })
  573. this.crud.delAllLoading = false
  574. this.crud.refresh()
  575. }).catch(err => {
  576. this.crud.delAllLoading = false
  577. console.log(err)
  578. })
  579. }).catch(() => {
  580. this.crud.delAllLoading = false
  581. })
  582. },
  583. handleCloseDialog() {
  584. this.markVisible = false
  585. this.crud.refresh()
  586. },
  587. initCanvasPreview(drawinfo) {
  588. this.canvasPreview = new fabric.Canvas('canvasPreview', {
  589. skipTargetFind: false,
  590. selectable: false,
  591. selection: false
  592. })
  593. this.canvasPreview.selectionColor = 'rgba(0,0,0,0.05)'
  594. this.loadDrawPreview(drawinfo)
  595. this.canvasPreview.on('mouse:wheel', this.mouse)
  596. },
  597. // 鼠标滚轮放大缩小
  598. mouse(e) {
  599. if (undefined === e) return
  600. let zoom = (e.e.deltaY > 0 ? -0.1 : 0.1) + this.canvasPreview.getZoom()
  601. zoom = Math.max(0.8, zoom)
  602. // 最小为原来的1/10
  603. zoom = Math.min(3, zoom)
  604. // 最大是原来的3倍
  605. const zoomPoint = new fabric.Point(e.e.pageX, e.e.pageY)
  606. this.canvasPreview.zoomToPoint(zoomPoint, zoom)
  607. },
  608. // 回显详情信息
  609. loadDrawPreview(drawinfo) {
  610. const self = this
  611. const pointGroup = drawinfo.pointInfo
  612. const imgInfo = drawinfo.imgInfo
  613. imgInfo.src = self.imageUrl
  614. // 加载底图
  615. fabric.util.enlivenObjects([imgInfo], objects => {
  616. objects.forEach(o => {
  617. o.selectable = false
  618. o.hasControls = false
  619. o.centeredScaling = false
  620. self.canvasPreview.add(o)
  621. })
  622. // 处理多边形绘制回显操作
  623. pointGroup.forEach(async(item, index) => {
  624. if (item.pointInfo !== '') {
  625. const polygon = new fabric.Polygon(item.pointInfo, {
  626. name: item.name,
  627. stroke: 'rgba(196,43, 1, 1)',
  628. strokeWidth: self.drawWidth,
  629. fill: 'rgba(196,43, 1, 1)',
  630. opacity: 0.5,
  631. selectable: false,
  632. hasBorders: false,
  633. hasControls: false,
  634. originX: 'left', // 设置原点为左上角
  635. originY: 'top' // 设置原点为左上角
  636. })
  637. // polygon.index = index
  638. self.canvasPreview.add(polygon)
  639. polygon.on('mousedown', function(e) {
  640. console.log('Rect ' + (index + 1) + ' clicked', e)
  641. console.log('e.target.name', e.target.name)
  642. })
  643. polygon.on('mouseover', function(e) {
  644. console.log('e', e)
  645. console.log('e.target', e.target)
  646. console.log('e.target.name', e.target.name)
  647. this.set({ opacity: 0.8, hoverCursor: 'pointer' })
  648. self.canvasPreview.renderAll()
  649. })
  650. // 监听鼠标移出事件
  651. polygon.on('mouseout', function() {
  652. this.set({ opacity: 0.5 })
  653. self.canvasPreview.renderAll()
  654. })
  655. }
  656. })
  657. })
  658. self.canvasPreview.renderAll()
  659. }
  660. }
  661. }
  662. </script>
  663. <style lang="scss" scoped>
  664. .tab-content{
  665. min-height: calc(100vh - 232px) !important;
  666. }
  667. </style>