index.tsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. import {
  2. ref,
  3. defineComponent,
  4. onMounted,
  5. computed,
  6. onUnmounted,
  7. reactive,
  8. watch,
  9. } from 'vue';
  10. import { useRouter, useRoute } from 'vue-router';
  11. import './index.scss';
  12. import { upload, UploadData } from '@/api/common';
  13. import { isArray } from 'lodash';
  14. import { useCommonStore, useIncidentStore } from '@/store';
  15. import { BaseMediaUrl, isImage, isVideo } from '@/utils';
  16. import {
  17. DropdownItemOption,
  18. NavBar,
  19. DropdownMenu,
  20. DropdownItem,
  21. Icon,
  22. PullRefresh,
  23. Sticky,
  24. Collapse,
  25. CollapseItem,
  26. Field,
  27. Button,
  28. Loading,
  29. Toast,
  30. Step,
  31. Steps,
  32. Dialog,
  33. Popup,
  34. Uploader,
  35. UploaderFileListItem,
  36. ImagePreview,
  37. } from 'vant';
  38. /** @ts-ignore */
  39. import icon_communication from '@/assets/icons/incident/communication@2x.png';
  40. /** @ts-ignore */
  41. import icon_detail from '@/assets/icons/incident/detail@2x.png';
  42. /** @ts-ignore */
  43. import icon_information from '@/assets/icons/incident/information@2x.png';
  44. /** @ts-ignore */
  45. import icon_plan from '@/assets/icons/incident/plan@2x.png';
  46. /** @ts-ignore */
  47. import icon_yjck from '@/assets/icons/incident/yjck@2x.png';
  48. /** @ts-ignore */
  49. import icon_yjya from '@/assets/icons/incident/yjya@2x.png';
  50. /** @ts-ignore */
  51. import icon_video from '@/assets/icons/incident/video.png';
  52. ;
  53. import { cloneDeep, take } from 'lodash';
  54. export default defineComponent({
  55. name: 'IncidentManagementDetail',
  56. setup() {
  57. const router = useRouter();
  58. const route = useRoute();
  59. const store = useIncidentStore();
  60. const commonStore = useCommonStore();
  61. const activeNames = ref([
  62. '事件信息',
  63. '应急预案',
  64. '处置方案',
  65. '处置详情',
  66. '融合通信',
  67. ]);
  68. const activeoplanNames = ref([
  69. ]);
  70. const message = ref('');
  71. const dosubmitdata = () => {
  72. if (!store.incidentDetail.baseInfo?.id || message.value == "") {
  73. Toast.fail('信息不完整');
  74. }
  75. store
  76. .addIncidentProcess({
  77. incidentId: store.incidentDetail.baseInfo?.id,
  78. des: message.value,
  79. taskId: currenttaskid.value,
  80. video: videosrclist.map((i: UploadData) => i.url).join(','),
  81. pic: imagessrclist.map((i: UploadData) => i.url).join(','),
  82. })
  83. .then(() => {
  84. message.value = '';
  85. videosrclist.splice(0);
  86. imagessrclist.splice(0);
  87. form.value = { pic: [], video: [] };
  88. store.getIncidentItem(store.incidentDetail.baseInfo?.id ?? '');
  89. });
  90. };
  91. const dohs = () => {
  92. try {
  93. uni.postMessage({
  94. data: {
  95. type: 'RHTX_gotoMeetMember',
  96. data: 'yjzh',
  97. },
  98. });
  99. } catch (E) {
  100. }
  101. }
  102. const planOptions = computed(
  103. () =>
  104. Object.keys(store.incidentDetail?.baseTask ?? {})
  105. .map((idx) => {
  106. const item = commonStore.globalDict['zhdd_incident_level']?.find(
  107. (i) =>
  108. i.dictValue ===
  109. store.incidentDetail?.baseTask?.[idx]?.[0].level?.toString(),
  110. );
  111. const desc = store.incidentDetail?.baseTask?.[idx]?.map(
  112. (i) => i.taskDes,
  113. );
  114. return {
  115. ...item,
  116. desc,
  117. };
  118. })
  119. ?.find(
  120. (item) =>
  121. item.dictValue?.toString() ===
  122. store.incidentDetail?.baseInfo?.level?.toString(),
  123. )?.desc,
  124. );
  125. const currenttaskid = ref('');
  126. const process = ref([]);
  127. const handleUpload = (file) => {
  128. Toast.loading({
  129. message: '上传中...',
  130. duration: 0,
  131. forbidClick: true,
  132. });
  133. upload(file)
  134. .then((res) => {
  135. Toast.clear();
  136. let type = /\w+([.jpg|.png|.gif|.swf|.bmp|.jpeg]){1}$/.test(
  137. res.data.fileName?.substr(
  138. res.data.fileName?.lastIndexOf('.') + 1,
  139. ) ?? '',
  140. );
  141. if (!type) {
  142. videosrclist.push(res.data);
  143. } else {
  144. imagessrclist.push(res.data);
  145. }
  146. })
  147. .catch((error) => {
  148. Toast.clear();
  149. });
  150. };
  151. watch(
  152. () => store.incidentDetail.process,
  153. () => {
  154. var mkdtemp = {};
  155. store.incidentDetail.process?.map((i) => {
  156. var list = mkdtemp[i.taskId] ?? [];
  157. list.push(i);
  158. mkdtemp[i.taskId] = list;
  159. });
  160. console.log(mkdtemp);
  161. process.value = [];
  162. store.incidentDetail.process?.map((i) => {
  163. var list = cloneDeep(mkdtemp[i.taskId] ?? []);
  164. if (i.taskId && list.length > 0 && list[0].id === i.id) {
  165. list.splice(0, 1);
  166. process.value.push({
  167. ...i,
  168. child: list,
  169. });
  170. } else {
  171. if (!i.taskId) {
  172. process.value.push({
  173. ...i,
  174. });
  175. }
  176. }
  177. });
  178. },
  179. );
  180. const form = ref({pic:[],video:[]});
  181. const videosrclist = reactive([]);
  182. const imagessrclist = reactive([]);
  183. const videop = ref();
  184. const videopsrc = ref('');
  185. const isshowprew = ref(false);
  186. onMounted(() => {
  187. commonStore.getGlobalDict('zhdd_incident_level');
  188. commonStore.getGlobalDict('zhdd_incident_type');
  189. commonStore.getGlobalDict('zhdd_incident_source');
  190. route.query.id && store.getIncidentItem(route.query.id as string);
  191. if (route.query.taskid) {
  192. currenttaskid.value = route.query.taskid as string;
  193. }
  194. });
  195. const getisbj = () => {
  196. if (currenttaskid.value == "")
  197. return true;
  198. var isok = false;
  199. store.incidentDetail.task?.map(ii => {
  200. if (ii.id == currenttaskid.value && ii.backLogFlag == "1") {
  201. isok = true;
  202. }
  203. })
  204. return isok;
  205. }
  206. onUnmounted(() => {
  207. store.incidentDetail = {};
  208. });
  209. return () => (
  210. <div class="incident-detail-container">
  211. <NavBar
  212. title="应急处置"
  213. left-arrow
  214. fixed
  215. onClick-left={() => {
  216. try {
  217. uni.navigateBack();
  218. } catch (E) {}
  219. //window.history.back();
  220. }}
  221. />
  222. <Sticky offsetTop={'46px'}>
  223. <div class="title">{store.incidentDetail?.baseInfo?.name}</div>
  224. </Sticky>
  225. <Popup
  226. style="width:100%;background:rgba(0,0,0,0)"
  227. v-model:show={isshowprew.value}
  228. onClose={() => {
  229. videop.value.pause();
  230. }}>
  231. <video
  232. ref={videop}
  233. src={videopsrc.value}
  234. controls
  235. autoplay="true"
  236. style="width:100%"></video>
  237. </Popup>
  238. <Collapse v-model={activeNames.value}>
  239. <CollapseItem
  240. title="处置方案"
  241. name="处置方案"
  242. v-slots={{ icon: <img class="icon-i" src={icon_plan} /> }}>
  243. {/* <Collapse v-model={activeoplanNames.value}> */}
  244. <div style={'color:#333'}>
  245. {store.incidentDetail.task
  246. ?.filter((i) => i.id == route.query.taskid)
  247. .map((i) => (
  248. <>
  249. <div>{i.taskName}</div>
  250. <div
  251. style={`color:#000;font-size:10px;font-weight:600;padding:6px 0;${
  252. i.chemicals != '' && i.chemicals != null
  253. ? ''
  254. : 'display:none'
  255. }`}>
  256. 危化品:
  257. {i.chemicalsText?.split(',').map((tt, indx) => (
  258. <span
  259. style={'color:#0B33A8;margin-right:10px'}
  260. onClick={() => {
  261. //查找id
  262. var idc = i.chemicals?.split(',')[indx];
  263. router.push(`/chemical/detail?id=${idc}`);
  264. }}>
  265. {tt}
  266. </span>
  267. ))}
  268. </div>
  269. </>
  270. ))}
  271. <div style={getisbj() ? 'display:none' : ''}>
  272. <div style={'padding:8px 0'}>
  273. <span style={'color:red'}>*</span>反馈内容
  274. </div>
  275. <Field
  276. v-model={message.value}
  277. autosize
  278. class={'textarea'}
  279. type="textarea"
  280. placeholder="请输入"
  281. />
  282. <div style={'height:13px;width:1px'}></div>
  283. <Field
  284. class={'uploadc'}
  285. v-slots={{
  286. input: () => (
  287. <Uploader
  288. accept="image/*"
  289. v-model={form.value.pic}
  290. max-size={20 * 1024 * 1024}
  291. onOversize={() => {
  292. Toast('最大支持20M的图片');
  293. }}
  294. onDelete={(filep, detail) => {
  295. imagessrclist.splice(detail.index, 1);
  296. console.log(imagessrclist);
  297. }}
  298. afterRead={(
  299. file: UploaderFileListItem | UploaderFileListItem[],
  300. ) => {
  301. handleUpload((isArray(file) ? file[0] : file).file);
  302. return false;
  303. }}
  304. />
  305. ),
  306. }}
  307. />
  308. <Field
  309. class={'uploadc'}
  310. v-slots={{
  311. input: () => (
  312. <Uploader
  313. accept="video/*"
  314. v-model={form.value.video}
  315. upload-icon={'video-o'}
  316. max-size={100 * 1024 * 1024}
  317. onOversize={() => {
  318. Toast('最大支持100M的视屏');
  319. }}
  320. afterRead={(
  321. file: UploaderFileListItem | UploaderFileListItem[],
  322. ) => {
  323. handleUpload((isArray(file) ? file[0] : file).file);
  324. return false;
  325. }}
  326. onDelete={(filep, detail) => {
  327. videosrclist.splice(detail.index, 1);
  328. console.log(videosrclist);
  329. }}
  330. onClick-preview={(index) => {
  331. isshowprew.value = true;
  332. try {
  333. videopsrc.value = URL.createObjectURL(index.file);
  334. videop.value.play();
  335. videop.value.currentTime = 0;
  336. } catch (error) {}
  337. }}
  338. />
  339. ),
  340. }}
  341. />
  342. <div class="cz-action">
  343. <Button
  344. size="small"
  345. type="primary"
  346. onClick={() => {
  347. dosubmitdata();
  348. }}>
  349. 保存
  350. </Button>
  351. <Button
  352. size="small"
  353. type="default"
  354. onClick={() => {
  355. message.value = '';
  356. form.value = { pic: [], video: [] };
  357. }}>
  358. 取消
  359. </Button>
  360. <Button
  361. color="red"
  362. style={getisbj() ? 'display:none' : ''}
  363. size="small"
  364. type="default"
  365. onClick={() => {
  366. if (getisbj()) {
  367. return;
  368. }
  369. Dialog.confirm({
  370. title: '提示',
  371. confirmButtonText: '办结',
  372. message:
  373. '点击办结按钮后,将无法继续反馈,请确认好是否完成!',
  374. })
  375. .then(() => {
  376. // on confirm
  377. store.putbackLog(currenttaskid.value);
  378. try {
  379. uni.navigateBack();
  380. } catch (E) {}
  381. })
  382. .catch(() => {
  383. // on cancel
  384. });
  385. }}>
  386. 办结
  387. </Button>
  388. </div>
  389. </div>
  390. </div>
  391. {/* </Collapse> */}
  392. </CollapseItem>
  393. <CollapseItem
  394. title="处置详情"
  395. name="处置详情"
  396. v-slots={{ icon: <img class="icon-i" src={icon_detail} /> }}>
  397. <div>
  398. {process.value
  399. ?.filter((i) => i.taskId === currenttaskid.value)
  400. .map((i, index) => (
  401. <div class="czxq-item">
  402. <div class="cz-yuan"></div>
  403. <div
  404. class="cz-line"
  405. style={`display:${
  406. index ==
  407. (process.value?.filter(
  408. (i) => i.taskId === currenttaskid.value,
  409. )?.length ?? 0) -
  410. 1
  411. ? 'none'
  412. : 'block'
  413. }`}></div>
  414. <div class="cz-time"> {i.createTime}</div>
  415. <div class="cz-des">
  416. {' '}
  417. {i.des}
  418. <div
  419. style={`margin-top: 4px;${
  420. (i.child ?? []).length > 0 ? '' : 'display:none'
  421. }`}
  422. class={i.taskId == currenttaskid.value ? 'active' : ''}>
  423. {(i.child ?? [])?.map((ii, index) => (
  424. <div class="czxq-item">
  425. <div class="cz-yuan"></div>
  426. <div
  427. class="cz-line"
  428. style={`display:${
  429. index == ((i.child ?? [])?.length ?? 0) - 1
  430. ? 'none'
  431. : 'block'
  432. }`}></div>
  433. <div class="cz-time"> {ii.createTime}</div>
  434. <div class="cz-des">
  435. <div style={'margin-bottom:8px'}>{ii.des}</div>
  436. <div
  437. class={'img'}
  438. style={
  439. ii.pic === '' && ii.video === ''
  440. ? 'display:none'
  441. : ''
  442. }>
  443. {((ii.pic ?? '') + ',' + (ii.video ?? '') ?? '')
  444. .split(',')
  445. .map((iim, idxq) => {
  446. iim = iim ?? '';
  447. if (isImage({ fileName: iim, url: iim })) {
  448. // console.log(iim);
  449. return (
  450. <img
  451. src={BaseMediaUrl + iim}
  452. onClick={() => {
  453. ImagePreview({
  454. images: ii.pic
  455. .split(',')
  456. .filter((cc) => cc != '')
  457. .map((cc) => {
  458. return BaseMediaUrl + cc;
  459. }),
  460. startPosition: idxq,
  461. });
  462. }}
  463. style={
  464. 'width:20px;height:30px;object-fit: contain;margin-right:10px;padding:0 10px;background:rgb(240 236 236);'
  465. }></img>
  466. );
  467. }
  468. if (isVideo({ fileName: iim, url: iim })) {
  469. // console.log(iim);
  470. return (
  471. <img
  472. onClick={() => {
  473. isshowprew.value = true;
  474. try {
  475. videopsrc.value =
  476. BaseMediaUrl + iim;
  477. videop.value.play();
  478. videop.value.currentTime = 0;
  479. } catch (error) {}
  480. }}
  481. src={icon_video}
  482. style={
  483. 'width:20px;height:30px;object-fit: contain;margin-right:10px;background:rgb(240 236 236);padding:0 10px;border-radius:4px'
  484. }></img>
  485. );
  486. }
  487. return <div></div>;
  488. })}
  489. </div>
  490. </div>
  491. </div>
  492. ))}
  493. </div>
  494. </div>
  495. </div>
  496. ))}
  497. <div onClick={() => {
  498. if (route.query.taskid) {
  499. router.push(
  500. `/status/${route.params.status}/detail?id=${route.query.id}&taskid=${route.query.taskid}`,
  501. );
  502. } else {
  503. router.push(
  504. `/status/${route.params.status}/detail?id=${route.query.id}`,
  505. );
  506. }
  507. }}
  508. style={
  509. 'padding-bottom: 30px; text-align: right; padding-top: 10px;padding-top:10px;color:#0B33A8'
  510. }>
  511. 查看详情
  512. </div>
  513. </div>
  514. </CollapseItem>
  515. </Collapse>
  516. </div>
  517. );
  518. },
  519. });