index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. <template>
  2. <div class="index_box">
  3. <div class="content_box">
  4. <!-- @tab-click="handleClick" -->
  5. <!-- 工序名称 -->
  6. <!-- <Search></Search> -->
  7. <div class="content_box_tab">
  8. <el-input
  9. style="width: 180px"
  10. clearable
  11. v-model="name"
  12. placeholder="请输入筛选项"
  13. @input="seekInput"
  14. />
  15. <el-tabs
  16. v-model="activeName"
  17. type="card"
  18. stretch
  19. @tab-click="tabClickValue"
  20. >
  21. <el-tab-pane label="工序" name="0">
  22. <el-tree
  23. :data="produceTaskList"
  24. :props="defaultProps"
  25. node-key="id"
  26. :highlight-current="true"
  27. @node-click="handleNodeClick"
  28. ref="taskListRef"
  29. >
  30. </el-tree>
  31. <!--
  32. v-loading="treeLoading"
  33. :node-key="nodeKey"
  34. ref="tree"
  35. :highlight-current="true"
  36. :expand-on-click-node="false"
  37. @node-click="handleNodeClick"
  38. v-bind="$attrs"
  39. :default-expand-all="defaultExpandAll" -->
  40. </el-tab-pane>
  41. <el-tab-pane label="工位" name="second">
  42. <!-- <AssetTree @handleNodeClick="handleNodeClickNew" @setRootId="setRootId" id="0" :paramsType="'type'"
  43. ref="treeList" eqDevice="sb" /> -->
  44. <el-tree
  45. :data="factoryworkstationList"
  46. :props="defaultPropsTow"
  47. node-key="id"
  48. :highlight-current="true"
  49. @node-click="handleNodeClick"
  50. >
  51. </el-tree>
  52. </el-tab-pane>
  53. </el-tabs>
  54. </div>
  55. <div style="width: calc(100% - 220px)">
  56. <div class="seek-list" style="background-color: #157a2c">
  57. <div>
  58. <el-input
  59. style="width: 180px; margin-right: 5px"
  60. clearable
  61. v-model="keyWord"
  62. placeholder="请输入关键字"
  63. @clear="handleSearch"
  64. />
  65. <!-- <el-input style="width: 180px" clearable v-model="taskName" placeholder="请输入工序进度" /> -->
  66. <!-- -->
  67. <el-button
  68. size="mini"
  69. type="primary"
  70. style="margin: 0 5px"
  71. @click="handleSearch"
  72. >查询</el-button
  73. >
  74. </div>
  75. <div
  76. style="
  77. width: 55%;
  78. color: #fff;
  79. display: flex;
  80. justify-content: space-between;
  81. "
  82. >
  83. <div>
  84. <b style="margin-right: 50px">当前工序:{{ title }}</b>
  85. <b>下道工序:{{ title1 }}</b>
  86. </div>
  87. <div> 操作员:{{ info.name }} </div>
  88. </div>
  89. </div>
  90. <ele-split-layout
  91. space="0px"
  92. width="45%"
  93. :resizable="true"
  94. :min-size="200"
  95. :max-size="-200"
  96. :left-style="{
  97. overflow: 'hidden',
  98. width: '100%'
  99. }"
  100. :right-style="{ overflow: 'hidden' }"
  101. :responsive="false"
  102. style="height: calc(100vh - 70px - 50px - 90px)"
  103. >
  104. <!-- 左侧 工单列表 -->
  105. <div class="left_main">
  106. <div class="top">
  107. <!-- /工单列表 -->
  108. <produceOrder
  109. @workSelect="workSelect"
  110. @rowClick="rowClick"
  111. ref="produceOrder"
  112. @getTaskName="getTaskName"
  113. >
  114. </produceOrder>
  115. </div>
  116. <!-- <div class="bottom">
  117. <productionResource :BomObj="BomObj"></productionResource>
  118. </div> -->
  119. </div>
  120. <!-- 右侧 详情 -->
  121. <template v-slot:content>
  122. <div class="right_main">
  123. <!-- 领料 -->
  124. <div v-if="operationType == 'pick'">
  125. <pickDetails
  126. ref="pickListRef"
  127. :workTaskId="workTaskId"
  128. @pickAdd="pickAdd"
  129. ></pickDetails>
  130. </div>
  131. <div v-if="operationType == 'feed'">
  132. <!-- 投料 -->
  133. <feeding
  134. :workListIds="workListIds"
  135. :feedNeedEquipment="feedNeedEquipment"
  136. ></feeding>
  137. </div>
  138. <div v-if="operationType == 'job'">
  139. <!-- // 报工列表 入库 -->
  140. <warehousing
  141. v-if="taskObj.id == -1"
  142. :workListIds="workListIds"
  143. ref="wareRef"
  144. ></warehousing>
  145. <!-- // 设备 入库 -->
  146. <!-- 普通报工 -->
  147. <jobBooking
  148. v-else
  149. :workListIds="workListIds"
  150. ref="jobRef"
  151. :reportNeedFeed="reportNeedFeed"
  152. ></jobBooking>
  153. <!-- <workPlan
  154. style="width: 100%"
  155. v-else
  156. :workListIds="workListIds"
  157. ref="jobRef"
  158. :reportNeedFeed="reportNeedFeed"
  159. >
  160. </workPlan> -->
  161. </div>
  162. <!-- 质检工序 -->
  163. <div v-if="operationType == 'inspection'">
  164. <inspection
  165. :workListIds="workListIds"
  166. ref="inspectionRef"
  167. ></inspection>
  168. </div>
  169. <!-- 委外 -->
  170. <div
  171. v-if="operationType == 'Outsourcing' && isType == '3'"
  172. class="right_main_box"
  173. >
  174. <outsourcing
  175. :outsourceFormVal="outsourceForm"
  176. @changePlugIn="changePlugIn"
  177. v-if="isStep"
  178. ></outsourcing>
  179. <!-- -->
  180. <outsourceList
  181. :outsourceFormVal="outObj"
  182. @closeForm="closeForm"
  183. @outScucc="outScucc"
  184. v-else
  185. ></outsourceList>
  186. </div>
  187. </div>
  188. </template>
  189. </ele-split-layout>
  190. <footBtn
  191. @footBtn="footBtn"
  192. :type="type"
  193. :singleReportInspection="singleReportInspection"
  194. style="background: rgba(223, 250, 222, 0.6); padding: 10px"
  195. ></footBtn>
  196. </div>
  197. <!-- <footBtn @footBtn="footBtn"></footBtn> -->
  198. </div>
  199. <!--领料弹框 -->
  200. <picking
  201. v-if="pickingShow"
  202. @close="pickingClose"
  203. :workListIds="workListIds"
  204. ></picking>
  205. <!-- 工艺文件 -->
  206. <wokePopup ref="wokePopupRef"></wokePopup>
  207. <!-- 检验报工 -->
  208. <workPlan ref="jobRefs"> </workPlan>
  209. <!-- <workes ref="jobRefs"> </workes> -->
  210. <!-- :workListIds="workListIds" :taskId="taskObj.id" -->
  211. </div>
  212. </template>
  213. <script>
  214. import Search from './components/search.vue';
  215. import footBtn from './components/footBtn.vue';
  216. // import produceOrder from './components/produceOrder.vue';
  217. import produceOrder from './components/new_produceOrder.vue';
  218. import productionResource from './components/productionResource/index.vue';
  219. import outsourcing from './components/outsourcing/index.vue';
  220. import picking from './components/picking/index.vue';
  221. import wokePopup from './components/picking/wokePopup.vue';
  222. import inspection from './components/inspection/index.vue';
  223. import pickDetails from './components/picking/details.vue';
  224. import AssetTree from '@/components/AssetTree/joobIndex.vue';
  225. import feeding from './components/feeding/index.vue';
  226. import jobBooking from './components/jobBooking/index.vue';
  227. import workPlan from './components/workPlan/index.vue';
  228. import workes from './components/workPlan/components/work.vue';
  229. import warehousing from './components/warehousing/index.vue';
  230. import outsourceList from './components/outsourcing/outsourceList.vue';
  231. import {
  232. getByTaskId,
  233. pcCheckOutsource,
  234. getTaskInstanceById,
  235. checkOutsourceMaterial,
  236. listTask,
  237. factoryworkstationPage,
  238. nextTask
  239. } from '@/api/produce/index';
  240. export default {
  241. components: {
  242. Search,
  243. footBtn,
  244. wokePopup,
  245. produceOrder,
  246. productionResource,
  247. outsourcing,
  248. picking,
  249. pickDetails,
  250. outsourceList,
  251. feeding,
  252. AssetTree,
  253. jobBooking,
  254. inspection,
  255. warehousing,
  256. workPlan,
  257. workes
  258. },
  259. data() {
  260. return {
  261. name: '',
  262. activeName: '0',
  263. taskName: '',
  264. keyWord: '', //搜索
  265. title: '',
  266. type: '',
  267. loading: false,
  268. operationType: null,
  269. workListIds: [],
  270. factoryworkstationList: [],
  271. title1: '',
  272. arr: [],
  273. arrTow: [],
  274. produceTaskList: [],
  275. isType: '',
  276. isStep: true,
  277. outsourceForm: {},
  278. outObj: {},
  279. pickingShow: false,
  280. wokePopup: false,
  281. BomObj: {},
  282. defaultProps: {
  283. children: 'children',
  284. label: 'newName'
  285. },
  286. defaultPropsTow: {
  287. children: 'children',
  288. label: 'name',
  289. value: 'code'
  290. },
  291. feedNeedEquipment: 0, //投料是否要添加生产设备1是0否
  292. reportNeedFeed: 0, //生产质检是否需要处置再报工1是0否
  293. singleReportInspection: null, //获取选中的工单是单个还是批量
  294. workTaskId: null, //选中的工单工序id
  295. workData: {}
  296. };
  297. },
  298. computed: {
  299. taskObj() {
  300. return this.$store.state.user.taskObj;
  301. },
  302. info() {
  303. return this.$store.state.user.info;
  304. }
  305. },
  306. created() {
  307. this.init();
  308. this.getTaskList();
  309. this.getFactoryworkstationPageList();
  310. this.operationType = null;
  311. this.workListIds = [];
  312. },
  313. methods: {
  314. tabClickValue() {
  315. this.name = '';
  316. this.seekInput();
  317. },
  318. // 前端筛选
  319. seekInput() {
  320. // console.log(activeName);
  321. if (this.activeName == '0') {
  322. if (!this.name) return (this.produceTaskList = this.arr);
  323. this.produceTaskList = this.produceTaskList.filter((item) => {
  324. return item.name.indexOf(this.name) > -1;
  325. });
  326. } else {
  327. if (!this.name) return (this.factoryworkstationList = this.arrTow);
  328. this.factoryworkstationList = this.factoryworkstationList.filter(
  329. (item) => {
  330. return item.name.indexOf(this.name) > -1;
  331. }
  332. );
  333. }
  334. },
  335. // 折叠悬浮中样式调整
  336. init() {
  337. this.$store.dispatch('theme/setCollapse', true);
  338. },
  339. async getTaskName(value) {
  340. if (value.length > 0) {
  341. let res = await nextTask({
  342. taskId: this.taskObj.id,
  343. workOrderIds: value.map((item) => item.id)
  344. });
  345. this.title1 = res.data.map((item) => item.taskTypeName).toString();
  346. } else {
  347. this.title1 = '';
  348. }
  349. },
  350. handleSearch() {
  351. let obj = {
  352. keyWord: this.keyWord,
  353. taskName: this.taskName
  354. };
  355. this.$refs.produceOrder.handleSearch(obj);
  356. //handleSearch(this.code);
  357. },
  358. handleNodeClickNew(info) {
  359. console.log(info, '999');
  360. // this.current = info;
  361. let current = { id: info.id };
  362. this.$store.commit('user/currentObj', current);
  363. },
  364. setRootId(id) {
  365. this.rootId = id;
  366. },
  367. // 点击工序
  368. handleNodeClick(data) {
  369. this.feedNeedEquipment = data.feedNeedEquipment;
  370. this.reportNeedFeed = data.reportNeedFeed;
  371. let obj = {
  372. 1: `${data.workCenterName}-${data.name}(普通工序)`,
  373. 3: `${data.workCenterName}-${data.name}(质检工序)`,
  374. 4: `${data.workCenterName}-${data.name}(包装工序)`,
  375. 5: `${data.workCenterName}-${data.name}(入库工序)`,
  376. 6: `${data.workCenterName}-${data.name}(质检工序)`
  377. };
  378. this.title = obj[data.type] || '';
  379. this.type = data.type;
  380. let taskObj = {};
  381. taskObj = this.produceTaskList.find((item) => item.id === data.id);
  382. this.$store.commit('user/setTaskObj', taskObj);
  383. },
  384. handleChoose(val) {
  385. console.log(val);
  386. },
  387. // 获取工序列表
  388. getTaskList() {
  389. listTask().then((res) => {
  390. res.map((v) => {
  391. v.newName = `${v.workCenterName}-${v.name}`;
  392. });
  393. this.produceTaskList = res;
  394. this.arr = JSON.parse(JSON.stringify(this.produceTaskList));
  395. //默认选择第一个工序
  396. if (this.produceTaskList?.length) {
  397. this.$store.commit('user/setTaskObj', this.produceTaskList[0]);
  398. this.$nextTick(() => {
  399. this.$refs.taskListRef.setCurrentKey(this.produceTaskList[0].id);
  400. });
  401. }
  402. // newName
  403. });
  404. },
  405. // 获取工位
  406. getFactoryworkstationPageList() {
  407. factoryworkstationPage({ pageNum: 1, size: 99999999 }).then((res) => {
  408. console.log(res, 'res');
  409. this.factoryworkstationList = res.list;
  410. this.arrTow = JSON.parse(JSON.stringify(this.factoryworkstationList));
  411. // newName
  412. });
  413. },
  414. closeForm() {
  415. this.isStep = true;
  416. },
  417. outScucc() {
  418. this.operationType = null;
  419. },
  420. // 切换组件
  421. async changePlugIn(e) {
  422. this.outObj = e;
  423. let req = {
  424. taskId: e.taskId,
  425. taskIds: e.taskIds,
  426. workOrderId: e.workOrderId,
  427. quantity: e.formedNumLast
  428. };
  429. const res = await checkOutsourceMaterial(req);
  430. this.outObj = { ...res.data, ...this.outsourceForm, ...this.outObj };
  431. this.isStep = false;
  432. },
  433. workSelect(data) {
  434. console.log(11112222, data);
  435. this.workTaskId = data.list.length > 0 ? data.list[0].taskId : null;
  436. this.singleReportInspection =
  437. data.list.length > 0 ? data.list[0].singleReport : null; //获取选中的工单是单个还是批量
  438. this.isStep = true;
  439. this.operationType = null;
  440. this.workListIds = data.ids;
  441. this.workData = data.list[0];
  442. },
  443. pickingWokeClose() {
  444. this.wokePopup = false;
  445. },
  446. footBtn(t) {
  447. this.operationType = t;
  448. if (
  449. Object.keys(this.$store.state.user.taskObj).length === 0 &&
  450. this.$store.state.user.taskObj.constructor === Object
  451. ) {
  452. this.$message.warning('请选择工序');
  453. return true;
  454. }
  455. if (['pick', 'feed', 'job'].includes(t)) {
  456. if (this.workListIds.length == 0) {
  457. this.$message.warning('请选择工单列表');
  458. return false;
  459. }
  460. }
  461. // console.log('按钮被点击了.....', t);
  462. if (t === 'job') {
  463. let req = {
  464. taskId: this.taskObj.id,
  465. workOrderId: this.workListIds[0],
  466. data: this.workData
  467. };
  468. if (this.taskObj.id == '1916800744740663298') {
  469. this.$refs.jobRefs.open(req);
  470. }
  471. }
  472. if (t == 'pick') {
  473. this.$nextTick(() => {
  474. this.$refs.pickListRef.getList(this.workListIds);
  475. });
  476. }
  477. // 工艺路线
  478. if (t === 'work') {
  479. let req = {
  480. taskId: this.taskObj.id,
  481. workOrderId: this.workListIds[0]
  482. };
  483. this.$refs.wokePopupRef.open(req);
  484. }
  485. if (t == 'feed') {
  486. }
  487. // 委外
  488. if (t == 'Outsourcing') {
  489. if (this.workListIds.length > 1) {
  490. return this.$message.warning('委外工序只能选择一个工单!');
  491. } else if (this.workListIds.length < 1)
  492. return this.$message.warning('请选择工单!');
  493. else {
  494. // /
  495. this.handOutsource(this.workListIds[0]);
  496. }
  497. }
  498. },
  499. handOutsource(workOrderId) {
  500. console.log(this.taskObj, workOrderId);
  501. // return
  502. let param = {
  503. taskId: this.taskObj.id,
  504. workOrderId: workOrderId
  505. };
  506. pcCheckOutsource(param).then((res) => {
  507. this.outsourceForm = {
  508. ...res.data
  509. };
  510. this.outsourceForm.name = this.taskObj.name + '委外';
  511. console.log(res, 'res');
  512. if (res.data.outsource) {
  513. this.isType = '3';
  514. this.getTaskInstanceByIdFn(workOrderId);
  515. } else {
  516. return this.$message.warning('此工序不能委外');
  517. }
  518. });
  519. },
  520. //获取工单列表
  521. getTaskInstanceByIdFn(workOrderId) {
  522. getTaskInstanceById(workOrderId).then((res) => {
  523. console.log(res, 'res');
  524. let { data } = res;
  525. if (data.length) {
  526. data = data.filter((item) => item.type == 1 || item.type == 4);
  527. let arr = data.findIndex(
  528. (item) => item.sourceTaskId == this.taskObj.id
  529. );
  530. console.log(arr);
  531. if (arr != -1) {
  532. data.splice(0, arr + 1);
  533. }
  534. console.log(data, '吃饭吃饭吃饭吃饭');
  535. this.$set(this.outsourceForm, 'newStepsList', data);
  536. }
  537. });
  538. },
  539. pickAdd() {
  540. this.pickingShow = true;
  541. },
  542. // 关闭领料弹窗
  543. pickingClose(val) {
  544. if (val) {
  545. this.$nextTick(() => {
  546. this.$refs.pickListRef.getList(this.workListIds);
  547. });
  548. }
  549. this.pickingShow = false;
  550. },
  551. rowClick(row, taskId) {
  552. console.log(row, taskId, 'row');
  553. if (taskId) {
  554. let params = {
  555. categoryId: row.categoryId,
  556. taskId: taskId
  557. };
  558. getByTaskId(params).then((res) => {
  559. this.BomObj = res.data;
  560. this.$forceUpdate();
  561. });
  562. }
  563. }
  564. },
  565. mounted() {
  566. this.$nextTick(() => {
  567. const targetElements =
  568. document.getElementsByClassName('ele-admin-tabs');
  569. if (targetElements.length > 0) {
  570. // 遍历所有具有 'ele-admin-tabs' 类的元素
  571. Array.from(targetElements).forEach((element) => {
  572. // 对每个元素添加 'new-ele-admin-tabs' 类
  573. element.classList.add('new-ele-admin-tabs');
  574. });
  575. }
  576. });
  577. },
  578. destroyed() {
  579. this.$nextTick(() => {
  580. const targetElements =
  581. document.getElementsByClassName('ele-admin-tabs');
  582. if (targetElements.length > 0) {
  583. Array.from(targetElements).forEach((element) => {
  584. element.classList.remove('new-ele-admin-tabs');
  585. });
  586. }
  587. });
  588. }
  589. };
  590. </script>
  591. <style>
  592. .content_box {
  593. display: flex;
  594. }
  595. .content_box_tab {
  596. width: 220px;
  597. padding: 5px;
  598. height: calc(100vh - 73px);
  599. background-color: #fff;
  600. overflow-y: auto;
  601. }
  602. .footBtn {
  603. position: absolute;
  604. bottom: 20px;
  605. left: 0;
  606. }
  607. .new-ele-admin-tabs {
  608. display: none !important;
  609. }
  610. .c_title {
  611. color: #157a2c;
  612. font-size: 16px;
  613. font-weight: bold;
  614. }
  615. .tableZ_box {
  616. border: 1px solid #e3e5e5;
  617. margin: 6px 0;
  618. &:last-child {
  619. border-bottom: none;
  620. }
  621. .row {
  622. width: 100%;
  623. display: flex;
  624. }
  625. .col {
  626. width: calc(100% / 5);
  627. display: flex;
  628. align-items: center;
  629. min-width: 200px;
  630. min-height: 32px;
  631. border-bottom: 1px solid #e3e5e5;
  632. border-right: 1px solid #e3e5e5;
  633. &:last-child {
  634. border-right: none;
  635. }
  636. .name {
  637. display: flex;
  638. align-items: center;
  639. padding: 4px;
  640. width: 80px;
  641. height: 100%;
  642. background-color: #d0e4d5;
  643. color: #000;
  644. }
  645. .content {
  646. padding: 4px 6px;
  647. color: #000;
  648. }
  649. }
  650. .pd6 {
  651. padding: 0 6px;
  652. }
  653. }
  654. </style>
  655. <style lang="scss" scoped>
  656. .seek-list {
  657. display: flex;
  658. justify-content: space-between;
  659. align-items: center;
  660. padding: 10px 10px;
  661. }
  662. .right_main_box {
  663. background-color: #fff;
  664. height: 100%;
  665. box-sizing: border-box;
  666. }
  667. .index_box {
  668. padding: 10px;
  669. padding-bottom: 0;
  670. width: 100%;
  671. box-sizing: border-box;
  672. min-width: 1280px !important;
  673. height: calc(100vh - 60px);
  674. // overflow-x: auto;
  675. /* 当内容超出宽度时,允许水平滚动 */
  676. white-space: nowrap;
  677. /* 防止内部文本换行,确保所有内容都在一行显示 */
  678. scrollbar-width: thin;
  679. /* 设置滚动条宽度(浏览器兼容性可能有所不同) */
  680. scrollbar-color: #40a9ff transparent;
  681. /* 设置滚动条颜色和轨道颜色(同样,浏览器兼容性) */
  682. }
  683. .main {
  684. width: 100%;
  685. min-width: 1280px;
  686. height: calc(100vh - 70px - 50px - 80px);
  687. display: flex;
  688. justify-content: space-between;
  689. }
  690. .left_main {
  691. width: 100%;
  692. height: 100%;
  693. display: flex;
  694. flex-direction: column;
  695. justify-content: space-around;
  696. min-width: 640px;
  697. .top {
  698. width: 100%;
  699. height: 100%;
  700. overflow: hidden;
  701. }
  702. // .bottom {
  703. // width: 100%;
  704. // min-height: calc((100vh - 70px - 50px - 80px - 20px) / 2);
  705. // overflow: hidden;
  706. // }
  707. }
  708. ::v-deep .el-tabs__item.is-active {
  709. background-color: #dffade;
  710. /* 蓝色背景 */
  711. color: #333;
  712. }
  713. ::v-deep .is-active {
  714. color: #dffade;
  715. }
  716. .right_main {
  717. min-width: 640px;
  718. padding-bottom: 12px;
  719. height: calc((100vh - 70px - 50px - 80px - 12px));
  720. background: #f0f3f3;
  721. }
  722. </style>