index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. <template>
  2. <div class="sandList-container">
  3. <div class="main-top">
  4. <el-button type="primary" @click="addSand">添加沙盘</el-button>
  5. <div>
  6. <el-input
  7. v-model="search_txt"
  8. style="width: 250px; margin-right: 20px"
  9. placeholder="沙盘名称"
  10. >
  11. <i slot="prefix" class="el-input__icon el-icon-search"></i>
  12. </el-input>
  13. <el-cascader
  14. :options="classifyArr"
  15. :props="classifyProps"
  16. v-model="classify"
  17. clearable
  18. placeholder="品种筛选"
  19. />
  20. </div>
  21. </div>
  22. <div class="main-bottom">
  23. <el-table
  24. :data="tableData"
  25. style="box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2)"
  26. :key="tableKey"
  27. row-key="VersionCode"
  28. :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
  29. :load="loadChildList"
  30. @sort-change="sortChangeHandle"
  31. element-loading-text="加载中..."
  32. v-loading="tableLoading"
  33. lazy
  34. border
  35. max-height="600"
  36. ref="table"
  37. >
  38. <el-table-column
  39. v-for="item in tableColums"
  40. :key="item.label"
  41. :label="item.label"
  42. :prop="item.key"
  43. :width="item.widthsty"
  44. :min-width="item.minwidthsty"
  45. :sortable="item.sortable"
  46. align="center"
  47. >
  48. <!-- :sortable="item.sortable?'custom':false" -->
  49. <template slot-scope="scope">
  50. <span>{{ scope.row[item.key] }}</span>
  51. <el-button
  52. size="mini"
  53. type="text"
  54. v-if="scope.row.key === 'more' && item.key === 'CurrVersion'"
  55. @click.native="openHistorySand(scope.row)"
  56. >更多</el-button
  57. >
  58. </template>
  59. </el-table-column>
  60. <el-table-column width="260" align="center" label="操作">
  61. <template slot-scope="scope">
  62. <template v-if="scope.row.key !== 'more'">
  63. <el-button
  64. type="text"
  65. @click="handleSand(scope.row, 'edit')"
  66. v-if="scope.row.CanEdit"
  67. >编辑</el-button
  68. >
  69. <el-button
  70. type="text"
  71. @click="handleSand(scope.row, 'edit')"
  72. v-if="!scope.row.CanEdit"
  73. >{{scope.row.Editor||''}}编辑中...</el-button
  74. >
  75. <el-button
  76. type="text"
  77. style="color: #f00"
  78. @click="handleSand(scope.row, 'del')"
  79. >删除</el-button
  80. >
  81. <el-button
  82. type="text"
  83. @click="handleSand(scope.row, 'view')"
  84. >查看</el-button
  85. >
  86. <el-button type="text" @click="copyImg(scope.row)"
  87. >复制图片</el-button
  88. >
  89. </template>
  90. </template>
  91. </el-table-column>
  92. <div slot="empty" style="padding: 50px 0 50px">
  93. <tableNoData text="暂无数据" size="mini"/>
  94. </div>
  95. </el-table>
  96. </div>
  97. <!-- 历史版本弹窗 -->
  98. <m-dialog
  99. :show.sync="openHistoryDia"
  100. width="700px"
  101. title="历史版本"
  102. @close="closeDialog"
  103. >
  104. <div class="history-version-wrapper">
  105. <el-table
  106. :data="historyList"
  107. style="box-shadow: 0px 3px 6px rgba(155, 170, 219, 0.2)"
  108. border
  109. >
  110. <el-table-column
  111. v-for="item in hitoryColums"
  112. :key="item.label"
  113. :label="item.label"
  114. :width="item.widthsty"
  115. :min-width="item.minwidthsty"
  116. align="center"
  117. >
  118. <template slot-scope="scope">
  119. <span>{{ scope.row[item.key] }}</span>
  120. </template>
  121. </el-table-column>
  122. <el-table-column align="center" label="操作">
  123. <template slot-scope="scope">
  124. <el-button type="text" @click="editChildSand(scope.row)" v-if="scope.row.CanEdit">编辑</el-button>
  125. <!-- <el-button type="text" @click="handleSand(scope.row, 'editing')" v-else>{{scope.row.Editor||''}}编辑中...</el-button> -->
  126. <el-button type="text" @click="editChildSand(scope.row)" v-else>{{scope.row.Editor||''}}编辑中...</el-button>
  127. <el-button type="text" style="color: #f00" @click="removeChildSand(scope.row)">删除</el-button>
  128. <el-button type="text" @click="handleSand(scope.row, 'view')">查看</el-button>
  129. <el-button type="text" @click="copyImg(scope.row)">复制图片</el-button>
  130. </template>
  131. </el-table-column>
  132. <div slot="empty" style="padding: 50px 0 50px">
  133. <tableNoData text="暂无数据" size="mini"/>
  134. </div>
  135. </el-table>
  136. <el-row style="margin-top: 30px">
  137. <m-page
  138. :page_no="history_page"
  139. :pageSize="history_pageSize"
  140. :total="history_total"
  141. @handleCurrentChange="hitoryPageChange"
  142. />
  143. </el-row>
  144. </div>
  145. </m-dialog>
  146. </div>
  147. </template>
  148. <script>
  149. import { sandInterface, customInterence } from '@/api/api.js';
  150. import mPage from '@/components/mPage';
  151. import mDialog from '@/components/mDialog';
  152. import { copyBlob } from '@/utils/svgToblob'
  153. export default {
  154. name: '',
  155. components: { mPage, mDialog },
  156. data() {
  157. return {
  158. search_txt: '',
  159. classify: [],
  160. classifyProps: {
  161. children: 'Items',
  162. label: 'ClassifyName',
  163. value: 'ChartPermissionId',
  164. },
  165. classifyArr: [],
  166. tableLoading: false,
  167. lockLoding:null,
  168. tableData: [],
  169. tableColums: [
  170. {
  171. label: '沙盘名称',
  172. key: 'Name',
  173. minwidthsty: '100px',
  174. },
  175. {
  176. label: '品种',
  177. key: 'ChartPermissionName',
  178. },
  179. {
  180. label: '版本',
  181. key: 'CurrVersion',
  182. widthsty: '100px',
  183. },
  184. {
  185. label: '更新时间',
  186. key: 'ModifyTime',
  187. minwidthsty: '120px',
  188. /* sortable:true */
  189. },
  190. {
  191. label: '更新人',
  192. key: 'OpUserName',
  193. widthsty: '120px',
  194. },
  195. ],
  196. page_no: 1,
  197. pageSize: 100,
  198. total: 0,
  199. openHistoryDia: false, //历史沙盘弹窗
  200. historyList: [],
  201. hitoryColums: [
  202. {
  203. label: '版本',
  204. key: 'CurrVersion',
  205. widthsty: '100px',
  206. },
  207. {
  208. label: '更新时间',
  209. key: 'ModifyTime',
  210. minwidthsty: '100px',
  211. },
  212. {
  213. label: '更新人',
  214. key: 'OpUserName',
  215. widthsty: '100px',
  216. },
  217. ], //历史表格数据列
  218. open_sandid: '', //打开的沙盘id
  219. history_page: 1,
  220. history_pageSize: 10,
  221. history_total: 0,
  222. tableBody:null,//表单body的dom,用于监听滚动事件
  223. tableKey: 0,//数据更新了 表格不更新的问题
  224. };
  225. },
  226. watch: {
  227. search_txt() {
  228. this.page_no = 1;
  229. this.getTableData();
  230. },
  231. classify() {
  232. this.page_no = 1;
  233. this.getTableData();
  234. },
  235. },
  236. methods: {
  237. /* 获取表格数据 */
  238. getTableData: _.debounce(function () {
  239. this.tableLoading = true;
  240. sandInterface
  241. .sandlist({
  242. PageSize: this.pageSize,
  243. CurrentIndex: this.page_no,
  244. Keyword: this.search_txt,
  245. ChartPermissionId: this.classify.length ? this.classify[1] : 0,
  246. })
  247. .then((res) => {
  248. if (res.Ret !== 200) return;
  249. const {Data} = res
  250. const {List,Paging} = Data
  251. const resData = List.length?res.Data.List.map((item) => ({
  252. hasChildren: item.VersionTotal > 1,
  253. ...item,
  254. ModifyTime: this.$moment(item.ModifyTime).format(
  255. 'YYYY-MM-DD HH:mm:ss'
  256. ),
  257. }))
  258. : [];
  259. this.tableData = this.page_no===1 ? resData : this.tableData.concat(resData);
  260. this.total = Paging.Totals;
  261. this.tableLoading = false;
  262. this.isLastPage = Paging.IsEnd
  263. this.tableKey ++;
  264. });
  265. }, 300),
  266. loadChildList(node, prop, resolve) {
  267. const { SandboxId,CanEdit } = node;
  268. sandInterface.childList({ SandboxId }).then((res) => {
  269. if (res.Ret !== 200) return;
  270. let arr = res.Data.List.length
  271. ? res.Data.List.map((item) => ({
  272. ...item,
  273. hide_name : item.Name,
  274. Name: '',
  275. ChartPermissionName: '',
  276. isChildList: true,
  277. ModifyTime: this.$moment(item.ModifyTime).format(
  278. 'YYYY-MM-DD HH:mm:ss'
  279. ),
  280. CanEdit
  281. }))
  282. : [];
  283. res.Data.Paging.Totals > 3
  284. ? resolve([
  285. ...arr,
  286. {
  287. key: 'more',
  288. VersionCode: new Date().getTime(),
  289. SandboxId: res.Data.List[0].SandboxId,
  290. },
  291. ])
  292. : resolve(arr);
  293. });
  294. },
  295. /* 获取品种 */
  296. getClassify() {
  297. customInterence
  298. .getvariety({
  299. CompanyType: 'ficc',
  300. })
  301. .then((res) => {
  302. if (res.Ret !== 200) return;
  303. this.classifyArr = res.Data.List;
  304. });
  305. },
  306. /* 添加沙盘 */
  307. addSand() {
  308. const { href } = this.$router.resolve({ path: '/sandflow' });
  309. window.open(href, '_blank');
  310. },
  311. goDetail(SandboxId, VersionCode, type) {
  312. const { href } = this.$router.resolve({
  313. path: '/sandflow',
  314. query: {
  315. id: VersionCode,
  316. type,
  317. },
  318. });
  319. window.open(href, '_blank');
  320. },
  321. /* 编辑 删除沙盘 */
  322. handleSand(item, type) {
  323. const { SandboxId, VersionCode } = item;
  324. if (type === 'edit') {
  325. // 编辑前校验
  326. sandInterface
  327. .mark({
  328. SandboxId,
  329. Status: 1,
  330. })
  331. .then((res) => {
  332. // if (res.Ret !== 200) return;
  333. if(res.Ret===200){
  334. if(res.Data.Status==1){
  335. this.$message.warning(res.Data.Msg || '沙盘图正在编辑,不可重复编辑')
  336. item.CanEdit=false;
  337. item.Editor=res.Data.Editor || ''
  338. return
  339. }else if(res.Data.Status==0){
  340. if(!item.CanEdit){
  341. this.getTableData();
  342. }
  343. // item.CanEdit=true;
  344. // item.Editor=res.Data.Editor || ''
  345. }
  346. }else{
  347. this.$message.error(res.ErrMsg || '未知错误,请稍后重试')
  348. return
  349. }
  350. this.goDetail(SandboxId, VersionCode, type);
  351. });
  352. }
  353. type === 'view' && this.goDetail(SandboxId, VersionCode, type);
  354. // type === 'editing' && this.$message.warning('沙盘图正在编辑,不可重复编辑');
  355. type === 'del' && this.delHandle(item)
  356. },
  357. /* 弹窗内的删除 */
  358. removeChildSand({VersionCode,Name,CurrVersion}) {
  359. this.$confirm(`<p>确定删除【<span style="color:#409EFF">${Name}</span>】沙盘图<span style="color:#409EFF">版本${CurrVersion}</span>?<p>`, '提示', {
  360. type: 'warning',
  361. dangerouslyUseHTMLString: true
  362. }).then(() => {
  363. sandInterface.sandDelVersion({ SandboxVersionCode:VersionCode }).then((res) => {
  364. if (res.Ret !== 200) return;
  365. this.$message.success('删除成功');
  366. this.historyList.splice(this.historyList.findIndex(_ => _.VersionCode === VersionCode),1)
  367. this.page_no = 1;
  368. this.getTableData();
  369. });
  370. }).catch(()=>{})
  371. },
  372. editChildSand(item) {
  373. ({SandboxId,VersionCode,type} = item)
  374. // 编辑前校验
  375. sandInterface
  376. .mark({
  377. SandboxId,
  378. Status: 1,
  379. })
  380. .then((res) => {
  381. // if (res.Ret !== 200) return;
  382. if(res.Ret===200){
  383. if(res.Data.Status==1){
  384. this.$message.warning(res.Data.Msg || '沙盘图正在编辑,不可重复编辑')
  385. item.CanEdit=false;
  386. item.Editor=res.Data.Editor || ''
  387. return
  388. }else if(res.Data.Status==0){
  389. if(!item.CanEdit){
  390. this.getTableData();
  391. }
  392. // item.CanEdit=true;
  393. // item.Editor=res.Data.Editor || ''
  394. }
  395. }else{
  396. this.$message.error(res.ErrMsg || '未知错误,请稍后重试')
  397. return
  398. }
  399. this.goDetail(SandboxId, VersionCode, type);
  400. });
  401. },
  402. /* 删除图 */
  403. delHandle(item) {
  404. const { SandboxId, VersionCode,isChildList,CurrVersion,hide_name } = item;
  405. isChildList
  406. ? this.$confirm(`<p>确定删除【<span style="color:#409EFF">${hide_name}</span>】沙盘图<span style="color:#409EFF">版本${CurrVersion}</span>?<p>`, '提示', {
  407. type: 'warning',
  408. dangerouslyUseHTMLString: true
  409. }).then(() => {
  410. sandInterface.sandDelVersion({ SandboxVersionCode:VersionCode }).then((res) => {
  411. if (res.Ret !== 200) return;
  412. this.$message.success('删除成功');
  413. this.page_no = 1;
  414. this.getTableData();
  415. });
  416. }).catch(()=>{})
  417. : this.$confirm('确定删除该沙盘图(包括所有历史版本)?', '提示', {
  418. type: 'warning',
  419. }).then(() => {
  420. sandInterface.sanDelete({ SandboxId }).then((res) => {
  421. if (res.Ret !== 200) return;
  422. this.$message.success('删除成功');
  423. this.page_no = 1;
  424. this.getTableData();
  425. });
  426. }).catch(()=>{});
  427. },
  428. /* 历史沙盘版本表格 */
  429. getHistoryTable(SandboxId) {
  430. sandInterface
  431. .verisonlist({
  432. PageSize: this.history_pageSize,
  433. CurrentIndex: this.history_page,
  434. SandboxId,
  435. })
  436. .then((res) => {
  437. if (res.Ret !== 200) return;
  438. this.historyList =
  439. res.Data.List &&
  440. res.Data.List.map((item) => ({
  441. ...item,
  442. ModifyTime: this.$moment(item.ModifyTime).format(
  443. 'YYYY-MM-DD HH:mm:ss'
  444. ),
  445. })) ||
  446. [];
  447. this.history_total = res.Data.Paging.Totals;
  448. });
  449. },
  450. /* 查看历史沙盘 */
  451. openHistorySand({ SandboxId }) {
  452. this.open_sandid = SandboxId;
  453. this.getHistoryTable(SandboxId);
  454. this.openHistoryDia = true;
  455. },
  456. /* 关闭弹窗 */
  457. closeDialog() {
  458. this.openHistoryDia = false;
  459. this.history_page = 1;
  460. },
  461. /* 复制图片 */
  462. copyImg: _.debounce(function ({ PicUrl }) {
  463. /* const copyImg = document.createElement('img');
  464. $('.sandList-container')[0].appendChild(copyImg);
  465. copyImg.src = PicUrl;
  466. this.getSelect(copyImg);
  467. setTimeout(() => {
  468. document.execCommand('copy');
  469. $('.sandList-container')[0].removeChild(copyImg);
  470. this.$message.success('复制成功');
  471. }); */
  472. this.lockLoding = this.$loading({
  473. lock: true,
  474. text: '复制图片中...',
  475. target: '.main-bottom',
  476. spinner: 'el-icon-loading',
  477. background: 'rgba(255, 255, 255, 0.8)'
  478. });
  479. const canvas = document.createElement("canvas");
  480. const ctx = canvas.getContext("2d");
  481. const img = new Image();
  482. img.crossOrigin = "Anonymous";
  483. img.src = PicUrl;
  484. img.onload = ()=>{
  485. canvas.width = img.width;
  486. canvas.height = img.height;
  487. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  488. ctx.fillStyle="#fff";
  489. ctx.fillRect(0, 0, img.width, img.height);
  490. ctx.drawImage(img, 0, 0);
  491. canvas.toBlob(async (blob) => {
  492. const data = [new ClipboardItem({ [blob.type]: blob })];
  493. await navigator.clipboard.write(data).then(
  494. () => {
  495. this.$message.success('复制成功!')
  496. },
  497. () => {
  498. this.$message.success('复制失败,稍后再试')
  499. }
  500. ).finally(()=>{
  501. this.lockLoding && this.lockLoding.close();
  502. });
  503. });
  504. }
  505. }, 500),
  506. /* 排序 */
  507. sortChangeHandle(sortInfo){
  508. const sortColumn = ['更新时间']
  509. const {column,order} = sortInfo
  510. if(!sortColumn.includes(column.label)) return
  511. //重新请求排序
  512. console.log(sortInfo)
  513. },
  514. /* 滚动条事件 */
  515. handleScroll:_.throttle(function(){
  516. const {scrollTop,clientHeight,scrollHeight} = this.tableBody
  517. if(scrollTop + clientHeight >= scrollHeight-10 && !this.isLastPage&&this.total!==this.tableData.length){
  518. this.page_no++;
  519. this.getTableData();
  520. }
  521. },300),
  522. // 选择
  523. getSelect(targetNode) {
  524. if (window.getSelection) {
  525. //chrome等主流浏览器
  526. var selection = window.getSelection();
  527. var range = document.createRange();
  528. range.selectNode(targetNode);
  529. selection.removeAllRanges();
  530. selection.addRange(range);
  531. } else if (document.body.createTextRange) {
  532. //ie
  533. var range = document.body.createTextRange();
  534. range.moveToElementText(targetNode);
  535. range.select();
  536. }
  537. },
  538. /* 页码改变 */
  539. handleCurrentChange(page) {
  540. this.page_no = page;
  541. this.getTableData();
  542. },
  543. hitoryPageChange(page) {
  544. this.history_page = page;
  545. this.getHistoryTable(this.open_sandid);
  546. },
  547. },
  548. mounted() {
  549. this.getTableData();
  550. this.getClassify();
  551. this.tableBody = this.$refs.table.bodyWrapper
  552. this.tableBody.addEventListener('scroll',this.handleScroll)
  553. },
  554. beforeDestroy(){
  555. this.tableBody.removeEventListener('scroll',this.handleScroll)
  556. }
  557. };
  558. </script>
  559. <style lang="scss">
  560. .sandList-container {
  561. .main-top {
  562. display: flex;
  563. justify-content: space-between;
  564. align-items: center;
  565. margin-bottom: 28px;
  566. padding: 20px 30px;
  567. background: #fff;
  568. border: 1px solid #ececec;
  569. border-radius: 4px;
  570. box-shadow: 0 3px 6px rgba(0, 0, 0, 0.05);
  571. }
  572. .main-bottom {
  573. padding: 20px 30px;
  574. background: #fff;
  575. border: 1px solid #ececec;
  576. border-radius: 4px;
  577. box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.05);
  578. .el-table {
  579. height:600px;
  580. .el-table__row--level-1 {
  581. td {
  582. border-right: none;
  583. }
  584. }
  585. .el-table__expand-icon {
  586. position: absolute;
  587. left: 5px;
  588. .el-icon-arrow-right {
  589. font-size: 14px;
  590. }
  591. }
  592. th.gutter{
  593. background-color:#F0F2F5 !important;
  594. }
  595. ::-webkit-scrollbar{
  596. background-color: transparent;
  597. &-track{
  598. background-color:#f5f5f5;
  599. }
  600. }
  601. }
  602. }
  603. .history-version-wrapper {
  604. padding: 0 20px;
  605. }
  606. }
  607. </style>