cameraScene.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629
  1. <template>
  2. <PageWrapper contentBackground>
  3. <template #footer>
  4. <a-tabs v-model:activeKey="tableType" @change="changeTable">
  5. <a-tab-pane :key="0" tab="四维看看" :disabled="loading" />
  6. <a-tab-pane :key="1" tab="四维看见" :disabled="loading" />
  7. <a-tab-pane :key="2" tab="深时点云场景" :disabled="loading" />
  8. <a-tab-pane :key="5" tab="深时Mesh场景" :disabled="loading" />
  9. <a-tab-pane :key="6" tab="深光点云场景" :disabled="loading" />
  10. <a-tab-pane :key="7" tab="深光Mesh场景" :disabled="loading" />
  11. <a-tab-pane :key="3" tab="四维双目Lite" :disabled="loading" />
  12. </a-tabs>
  13. </template>
  14. <div class="desc-wrap-BasicTable">
  15. <BasicTable @register="registerTable" ref="tableRef">
  16. <template #toolbar>
  17. <!-- <a-button type="primary" @click="exportExcel"> 导出1</a-button> -->
  18. </template>
  19. <template #status="{ record }">
  20. <span v-if="record.status != '-1'">{{ record.statusString }}</span>
  21. <Tooltip v-else placement="right">
  22. <template #title>
  23. <span>失败原因:{{ record.buildErrorReason }}</span>
  24. <p>
  25. <span>serverPath:{{ record.dataSource }}</span>
  26. </p>
  27. </template>
  28. <span
  29. >{{ record.statusString }}
  30. <Icon icon="mdi:warning-octagon-outline" />
  31. </span>
  32. </Tooltip>
  33. </template>
  34. <template #href="{ record }">
  35. <a
  36. v-if="record.sceneName && record.thumb"
  37. target="_blank"
  38. :href="record.webSite || record.thumb"
  39. >{{ record.sceneName }}</a
  40. >
  41. <span v-else-if="record.sceneName">{{ record.sceneName }}</span>
  42. <span v-else>-</span>
  43. </template>
  44. <template #action="{ record }">
  45. <TableAction
  46. stopButtonPropagation
  47. :actions="[
  48. {
  49. label: '迁移',
  50. disabled: !(record.status == 1 || record.status == -2),
  51. ifShow: getTypeCheckPerm('scenes-move') && tableType != 3,
  52. onClick: handleMove.bind(null, record),
  53. },
  54. {
  55. label: '解冻',
  56. disabled: !record.isColdStorage || !(record.status == 1 || record.status == -2),
  57. ifShow: getTypeCheckPerm('scenes-thaw'),
  58. onClick: handleColdStorage.bind(null, record),
  59. },
  60. {
  61. label: '下载',
  62. ifShow: getTypeCheckPerm('scenes-download') && tableType != 3,
  63. disabled: !(record.status == 1 || (record.status == -2 && record.payStatus == 1)),
  64. //icon: 'carbon:download',
  65. onClick: handleDownload.bind(null, record),
  66. },
  67. {
  68. label: '重算',
  69. disabled: record.status == 0 || (record.status == -2 && record.payStatus != 1),
  70. ifShow: getTypeCheckPerm('scenes-recalculate') && tableType != 3,
  71. popConfirm: {
  72. title: '是否重算?',
  73. confirm: handleReset.bind(null, record),
  74. },
  75. },
  76. {
  77. label: '复制',
  78. disabled: !(record.status == 1 || (record.status == -2 && record.payStatus == 1)),
  79. ifShow: getTypeCheckPerm('scenes-copy') && tableType != 3,
  80. onClick: handleCopy.bind(null, record),
  81. },
  82. {
  83. label: '删除',
  84. //icon: 'ic:outline-delete-outline',
  85. color: 'error',
  86. ifShow: getTypeCheckPerm('scenes-delete'),
  87. disabled: record.status == 0,
  88. //onClick: handleDelete.bind(null, record),
  89. popConfirm: {
  90. title: '是否删除?',
  91. confirm: handleDelete.bind(null, record),
  92. placement: 'topRight',
  93. },
  94. },
  95. ]"
  96. />
  97. </template>
  98. </BasicTable>
  99. </div>
  100. <DownLoadModal
  101. :downloadOption="downloadOption"
  102. @cancel="afterClose"
  103. @register="registerDownModal"
  104. @update="reload"
  105. cancelText="取消下载"
  106. okText="下载"
  107. @cancelDownload="cancelDownload"
  108. :okButtonProps="{ disabled: canDownload }"
  109. />
  110. <MoveModal @update="reload" @register="registerMoveModal" />
  111. </PageWrapper>
  112. </template>
  113. <script lang="ts">
  114. import { defineComponent, h, reactive, toRefs, ref, unref } from 'vue';
  115. import {
  116. BasicTable,
  117. useTable,
  118. TableAction,
  119. BasicColumn,
  120. TableActionType,
  121. TableImg,
  122. FormProps,
  123. } from '/@/components/Table';
  124. import { PageWrapper } from '/@/components/Page';
  125. import DownLoadModal from './modal/DownLoadModal.vue';
  126. import MoveModal from './modal/MoveModal.vue';
  127. import { Time } from '/@/components/Time';
  128. import { Icon } from '/@/components/Icon';
  129. import { Descriptions, Tabs, Progress, Tooltip } from 'ant-design-vue';
  130. import { useI18n } from '/@/hooks/web/useI18n';
  131. import { useMessage } from '/@/hooks/web/useMessage';
  132. import { useModal } from '/@/components/Modal';
  133. import {
  134. operateSceneList,
  135. sceneMove,
  136. sceneDelete,
  137. sceneReset,
  138. sceneRestStore,
  139. sceneDownload,
  140. checkDownLoad,
  141. downloadProcess,
  142. sceneCopy,
  143. rebuildScene,
  144. } from '/@/api/operate';
  145. import { message } from 'ant-design-vue';
  146. import { usePermissionStore } from '/@/store/modules/permission';
  147. import { func } from 'vue-types';
  148. import { truncate } from 'fs/promises';
  149. export default defineComponent({
  150. components: {
  151. DownLoadModal,
  152. MoveModal,
  153. BasicTable,
  154. TableAction,
  155. PageWrapper,
  156. Icon,
  157. Tooltip,
  158. [Descriptions.name]: Descriptions,
  159. [Descriptions.Item.name]: Descriptions.Item,
  160. [Tabs.name]: Tabs,
  161. [Tabs.TabPane.name]: Tabs.TabPane,
  162. },
  163. setup() {
  164. const { t } = useI18n();
  165. const { createMessage, createConfirm } = useMessage();
  166. const permissionStore = usePermissionStore();
  167. const { getCheckPerm } = permissionStore;
  168. const loading = ref(false);
  169. const tableRef = ref<Nullable<TableActionType>>(null);
  170. const tableType = ref<Number>(0); //0看看 、1看见、2深时
  171. function columns(isobj): BasicColumn[] {
  172. return [
  173. {
  174. title: '场景标题',
  175. dataIndex: 'sceneName',
  176. slots: { customRender: 'href' },
  177. width: 150,
  178. },
  179. {
  180. title: '场景码',
  181. dataIndex: 'num',
  182. ellipsis: true,
  183. width: 180,
  184. },
  185. {
  186. title: '拍摄时间',
  187. dataIndex: 'createTime',
  188. sorter: true,
  189. width: 180,
  190. customRender: ({ record }) => {
  191. return (
  192. record.createTime &&
  193. h(Time, {
  194. value: record.createTime,
  195. mode: 'datetime',
  196. })
  197. );
  198. },
  199. },
  200. {
  201. title: 'obj生成状态',
  202. dataIndex: 'isObj',
  203. ellipsis: true,
  204. ifShow: isobj,
  205. width: 180,
  206. customRender: ({ record }) => {
  207. return record.isObj == 0 ? '未生成' : record.isObj == 1 ? '已生成' : '计算中';
  208. },
  209. },
  210. {
  211. title: '计算完成时间',
  212. dataIndex: 'amount',
  213. width: 180,
  214. customRender: ({ record }) => {
  215. return (
  216. (record.algorithmTime &&
  217. h(Time, {
  218. value: record.algorithmTime,
  219. mode: 'datetime',
  220. })) ||
  221. '-'
  222. );
  223. },
  224. },
  225. {
  226. title: 'SN码',
  227. dataIndex: 'snCode',
  228. width: 180,
  229. },
  230. {
  231. title: '点位数量',
  232. dataIndex: 'shootCount',
  233. width: 80,
  234. },
  235. {
  236. title: '场景大小',
  237. dataIndex: 'sceneSize',
  238. width: 80,
  239. customRender: ({ record }) => {
  240. return record.sceneSize && record.sceneSize != 0
  241. ? h('span', { class: 'sceneSize' }, Math.ceil(record.sceneSize / 1024 / 1024) + 'M')
  242. : '-';
  243. },
  244. },
  245. {
  246. title: '拍摄位置',
  247. dataIndex: 'addressComponent',
  248. width: 100,
  249. customRender: ({ record }) => {
  250. if (!record.addressComponent) {
  251. return '';
  252. }
  253. return record && record.addressComponent && record.addressComponent.city; // + district + township;
  254. },
  255. },
  256. {
  257. title: '是否复制',
  258. dataIndex: 'isCopy',
  259. width: 80,
  260. customRender: ({ record }) => {
  261. return record.isCopy ? '是' : '否';
  262. },
  263. },
  264. {
  265. title: '复制时间',
  266. dataIndex: 'copyTime',
  267. width: 180,
  268. customRender: ({ record }) => {
  269. return record.copyTime
  270. ? h(Time, {
  271. value: record.copyTime,
  272. mode: 'datetime',
  273. })
  274. : '-';
  275. },
  276. },
  277. {
  278. title: '绑定账号',
  279. dataIndex: 'userName',
  280. width: 100,
  281. },
  282. {
  283. title: '浏览量',
  284. dataIndex: 'viewCount',
  285. sorter: true,
  286. width: 80,
  287. },
  288. {
  289. title: '状态',
  290. dataIndex: 'statusString',
  291. width: 120,
  292. slots: { customRender: 'status' },
  293. },
  294. {
  295. title: '操作',
  296. dataIndex: 'action',
  297. slots: { customRender: 'action' },
  298. ifShow: true,
  299. fixed: 'right',
  300. flag: 'ACTION',
  301. width: 280,
  302. },
  303. ];
  304. }
  305. // const searchForm: Partial<FormProps> = {
  306. // labelWidth: 100,
  307. // schemas: [
  308. // {
  309. // field: 'sceneName',
  310. // label: '场景标题',
  311. // component: 'Input',
  312. // componentProps: {
  313. // maxLength: 100,
  314. // },
  315. // colProps: {
  316. // xl: 7,
  317. // xxl: 7,
  318. // },
  319. // },
  320. // {
  321. // field: 'snCode',
  322. // label: 'SN码',
  323. // component: 'Input',
  324. // componentProps: {
  325. // maxLength: 100,
  326. // },
  327. // colProps: {
  328. // xl: 7,
  329. // xxl: 7,
  330. // },
  331. // },
  332. // {
  333. // field: 'userName',
  334. // label: '绑定账号',
  335. // component: 'Input',
  336. // componentProps: {
  337. // maxLength: 100,
  338. // },
  339. // colProps: {
  340. // xl: 6,
  341. // xxl: 6,
  342. // },
  343. // },
  344. // ],
  345. // };
  346. const searchFormSs: Partial<FormProps> = {
  347. labelWidth: 100,
  348. autoSubmitOnEnter: true,
  349. autoAdvancedLine: 1,
  350. actionColOptions: {
  351. span: 24,
  352. },
  353. schemas: [
  354. {
  355. field: 'sceneName',
  356. label: '场景标题',
  357. component: 'Input',
  358. componentProps: {
  359. maxLength: 100,
  360. },
  361. colProps: {
  362. xl: 7,
  363. xxl: 7,
  364. },
  365. },
  366. {
  367. field: 'num',
  368. label: '场景码',
  369. component: 'Input',
  370. componentProps: {
  371. maxLength: 100,
  372. },
  373. colProps: {
  374. xl: 7,
  375. xxl: 7,
  376. },
  377. },
  378. {
  379. field: 'snCode',
  380. label: 'SN码',
  381. component: 'Input',
  382. componentProps: {
  383. maxLength: 100,
  384. },
  385. colProps: {
  386. xl: 7,
  387. xxl: 7,
  388. },
  389. },
  390. {
  391. field: 'userName',
  392. label: '绑定账号',
  393. component: 'Input',
  394. componentProps: {
  395. maxLength: 100,
  396. },
  397. colProps: {
  398. xl: 7,
  399. xxl: 7,
  400. },
  401. },
  402. {
  403. field: 'timeList',
  404. label: '拍摄时间段',
  405. component: 'RangePicker',
  406. componentProps: {
  407. maxLength: 100,
  408. minWidth: '385px',
  409. format: 'YYYY-MM-DD',
  410. valueFormat: 'YYYY-MM-DD',
  411. showTime: true,
  412. },
  413. colProps: {
  414. xl: 8,
  415. xxl: 8,
  416. },
  417. },
  418. ],
  419. };
  420. function cancelDownload() {
  421. downloadOption.value = {};
  422. }
  423. const [registerDownModal, { openModal: openDownModal }] = useModal();
  424. const [registerMoveModal, { openModal: openMoveModal }] = useModal();
  425. const [registerTable, { reload, setColumns }] = useTable({
  426. api: operateSceneList,
  427. title: `场景列表`,
  428. columns: columns(false),
  429. searchInfo: { type: tableType },
  430. useSearchForm: true,
  431. formConfig: searchFormSs,
  432. showTableSetting: true,
  433. beforeFetch: (T) => {
  434. loading.value = true;
  435. return T;
  436. },
  437. afterFetch: (T) => {
  438. loading.value = false;
  439. return T;
  440. },
  441. rowKey: 'num',
  442. fetchSetting: {
  443. pageField: 'pageNum',
  444. sizeField: 'pageSize',
  445. listField: 'list',
  446. totalField: 'total',
  447. },
  448. canResize: true,
  449. });
  450. function getTableAction() {
  451. const tableAction = unref(tableRef);
  452. if (!tableAction) {
  453. console.log('tableAction', tableAction, tableRef);
  454. throw new Error('tableAction is null');
  455. }
  456. return tableAction;
  457. }
  458. function changeTable(val: string) {
  459. tableType.value = val;
  460. setColumns(columns(val == 2));
  461. // setColumns(columns)
  462. reload();
  463. }
  464. async function handleCopy(record: Recordable) {
  465. createConfirm({
  466. title: '复制场景',
  467. content: '复制场景,场景归属在原相机下。<br/>确定要复制场景吗?',
  468. onOk: async () => {
  469. sceneCopy({ num: record.num }).then(() => {
  470. message.success({
  471. content: '复制成功',
  472. });
  473. reload();
  474. });
  475. },
  476. });
  477. }
  478. async function handleDelete(record: Recordable) {
  479. console.log('handleDelete', record);
  480. // createConfirm({
  481. // title: '删除',
  482. // content: '确定要删除场景吗?',
  483. // onOk: async () => {
  484. sceneDelete({ num: record.num }).then(() => {
  485. message.success({
  486. content: '删除成功',
  487. });
  488. reload();
  489. });
  490. // },
  491. // });
  492. }
  493. async function handleColdStorage(record: Recordable) {
  494. createConfirm({
  495. title: '删除',
  496. content: '确定要解冻场景吗?',
  497. onOk: async () => {
  498. sceneRestStore({ num: record.num }).then(() => {
  499. message.success({
  500. content: '已提交解冻',
  501. });
  502. reload();
  503. });
  504. },
  505. });
  506. }
  507. async function handleMove(record: Recordable) {
  508. openMoveModal(true, {
  509. ...record,
  510. });
  511. }
  512. let timer: null = ref(null);
  513. const downloadOption = ref<Object>({});
  514. const canDownload = ref<boolean>(true);
  515. function handleDownload(record: Recordable) {
  516. console.log('handleDownload', record, tableType.value);
  517. let isObj = tableType.value == 5 ? 1 : 0;
  518. let params = { num: record.num, isObj: 0 };
  519. if (tableType.value == 4 || tableType.value == 5) {
  520. params.isObj = isObj;
  521. }
  522. canDownload.value = true;
  523. checkDownLoad(params).then((res) => {
  524. if (res.downloadStatus != 3) {
  525. // 未下载过,需要打包
  526. sceneDownload(params).then((res) => {
  527. console.log(res);
  528. openDownModal(true, {
  529. ...record,
  530. isObj: params.isObj,
  531. });
  532. if (res.downloadStatus == 1) {
  533. if (timer.value) {
  534. afterClose();
  535. }
  536. timer.value = setInterval(() => {
  537. downloadProcess(params).then((res) => {
  538. if (res.status == '1003') {
  539. createMessage.error('下载失败');
  540. afterClose();
  541. return;
  542. }
  543. if (res.percent >= 100) {
  544. canDownload.value = false;
  545. afterClose();
  546. }
  547. downloadOption.value = res;
  548. console.log(res);
  549. });
  550. }, 1000);
  551. }
  552. });
  553. } else {
  554. canDownload.value = false;
  555. window.open(res.downloadUrl);
  556. }
  557. });
  558. }
  559. function afterClose() {
  560. clearInterval(timer.value);
  561. timer.value = null;
  562. }
  563. function handleReset(record: Recordable) {
  564. console.log('handleReset', record);
  565. rebuildScene({ num: record.num }).then(() => {
  566. message.success({
  567. content: '操作成功',
  568. });
  569. reload();
  570. });
  571. }
  572. function getTypeCheckPerm(val) {
  573. let myType = tableType.value;
  574. return getCheckPerm(val) || getCheckPerm(`${val}-${myType}`);
  575. }
  576. return {
  577. registerTable,
  578. handleDelete,
  579. handleCopy,
  580. handleMove,
  581. handleDownload,
  582. handleReset,
  583. handleColdStorage,
  584. tableType,
  585. loading,
  586. reload,
  587. changeTable,
  588. t,
  589. openDownModal,
  590. registerDownModal,
  591. registerMoveModal,
  592. afterClose,
  593. timer,
  594. canDownload,
  595. downloadOption,
  596. cancelDownload,
  597. getTypeCheckPerm,
  598. };
  599. },
  600. });
  601. </script>
  602. <style lang="less" scoped>
  603. // .tableHeader {
  604. // height: 50px;
  605. // display: flex;
  606. // align-items: center;
  607. // .item {
  608. // font-size: 14px;
  609. // color: #666;
  610. // margin-right: 10px;
  611. // cursor: pointer;
  612. // &.active {
  613. // font-weight: bold;
  614. // color: #222;
  615. // }
  616. // }
  617. // }
  618. .desc-wrap-BasicTable {
  619. background-color: #f0f2f5;
  620. .vben-basic-table-form-container {
  621. padding: 0;
  622. }
  623. }
  624. </style>