index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. <template>
  2. <div class="ele-body">
  3. <el-card shadow="never" v-loading="loading">
  4. <el-form
  5. ref="form"
  6. :model="form"
  7. :rules="{}"
  8. label-width="120px"
  9. class="el-form-box"
  10. >
  11. <div style="display: flex">
  12. <el-form-item label="工厂名称:" prop="factoriesId">
  13. <el-select
  14. v-model="form.factoriesId"
  15. placeholder="请选择"
  16. @change="change_factoryId"
  17. >
  18. <el-option
  19. v-for="item in factoriesList"
  20. :label="item.factoryName"
  21. :value="item.factoryId"
  22. :key="item.factoryId"
  23. @click.native="form.factoriesName = item.factoryName"
  24. ></el-option>
  25. </el-select>
  26. </el-form-item>
  27. <el-form-item label="产线名称:" prop="productionLineId">
  28. <el-select v-model="form.productionLineId" placeholder="请选择">
  29. <el-option
  30. v-for="item in productionLineList"
  31. :label="item.name"
  32. :value="item.id"
  33. @click.native="change_productionLine(item)"
  34. :key="item.id"
  35. ></el-option>
  36. </el-select>
  37. </el-form-item>
  38. <el-form-item label="工位名称:" prop="workStationId">
  39. <el-select v-model="form.workStationId" placeholder="请选择">
  40. <el-option
  41. v-for="item in workStationList"
  42. :label="item.name"
  43. :value="item.id"
  44. @click.native="form.workStationName = item.name"
  45. :key="item.id"
  46. ></el-option>
  47. </el-select>
  48. </el-form-item>
  49. <!-- <el-form-item>
  50. <el-button
  51. type="primary"
  52. icon="el-icon-search"
  53. class="ele-btn-icon"
  54. @click="search"
  55. >
  56. 查询
  57. </el-button>
  58. <el-button @click="reset" icon="el-icon-refresh-left"
  59. >重置</el-button
  60. >
  61. </el-form-item> -->
  62. </div>
  63. </el-form>
  64. <div style="display: flex">
  65. <div class="calendar-container">
  66. <el-calendar v-model="timeValue">
  67. <template #dateCell="{ date, data }">
  68. <div
  69. class="calendar-day"
  70. @click="handleDateClick(date)"
  71. :class="{ 'selected-date': isSelected(date) }"
  72. >
  73. <div class="datetext">{{
  74. data.day.split('-').slice(2).join('-')
  75. }}</div>
  76. <div class="lunar-date">{{ lunarDate(date) }}</div>
  77. </div>
  78. </template>
  79. </el-calendar>
  80. </div>
  81. <el-form ref="form" :rules="{}" label-width="300px" class="el-form-box">
  82. <el-form-item label="生产班次" prop="code">
  83. <el-select
  84. v-model="productionShift"
  85. multiple
  86. placeholder="请选择"
  87. style="width: calc(100% - 75px)"
  88. >
  89. <el-option
  90. v-for="item in productionShiftList"
  91. :key="item.code"
  92. :label="item.shiftName"
  93. :value="item.code"
  94. >
  95. </el-option>
  96. </el-select>
  97. <el-button
  98. size="small"
  99. type="primary"
  100. icon="el-icon-plus"
  101. class="ele-btn-icon"
  102. @click="selectProductionShiftList"
  103. style="margin-left: 5px"
  104. >
  105. 适用
  106. </el-button>
  107. </el-form-item>
  108. </el-form>
  109. </div>
  110. <div>
  111. <!-- <el-button
  112. size="small"
  113. type="primary"
  114. icon="el-icon-plus"
  115. class="ele-btn-icon"
  116. @click="handleAddOrEdit()"
  117. >
  118. 新增行
  119. </el-button> -->
  120. <el-button
  121. size="small"
  122. type="primary"
  123. class="ele-btn-icon"
  124. @click="edit()"
  125. >
  126. 编辑
  127. </el-button>
  128. </div>
  129. <searchTable
  130. :productionLineList="productionLineList"
  131. :productionShiftList="productionShiftList"
  132. @search="search"
  133. ></searchTable>
  134. <!-- 数据表格 -->
  135. <ele-pro-table
  136. :ref="'table'"
  137. :columns="columns"
  138. :datasource="datasource"
  139. height="600px"
  140. full-height="calc(100vh - 116px)"
  141. tool-class="ele-toolbar-form"
  142. :selection.sync="selection"
  143. @columns-change="handleColumnChange"
  144. :cache-key="cacheKeyUrl"
  145. style="margin-top: 10px"
  146. row-key="id"
  147. >
  148. <template v-slot:action="{ row }">
  149. <el-link
  150. type="primary"
  151. :underline="false"
  152. icon="el-icon-edit"
  153. @click="edit(row)"
  154. >
  155. 修改
  156. </el-link></template
  157. >
  158. </ele-pro-table>
  159. </el-card>
  160. <!-- <add-or-edit-dialog
  161. ref="addOrEditDialogRef"
  162. @done="reload"
  163. ></add-or-edit-dialog> -->
  164. <!-- <process-submit-dialog
  165. :processSubmitDialogFlag.sync="processSubmitDialogFlag"
  166. v-if="processSubmitDialogFlag"
  167. ref="processSubmitDialogRef"
  168. @reload="reload"
  169. :isNotNeedProcess="false"
  170. ></process-submit-dialog> -->
  171. <timeTable ref="timeTableRef" @reload="reload"></timeTable>
  172. </div>
  173. </template>
  174. <script>
  175. import tabMixins from '@/mixins/tableColumnsMixin';
  176. // import addOrEditDialog from './components/addOrEditDialog.vue';
  177. import {
  178. getTableList,
  179. saveOrUpdate
  180. } from '@/api/productionScheduling/workCalendar';
  181. import {
  182. getTableList as getProductionShift,
  183. selectProductionShiftList
  184. } from '@/api/productionScheduling/productionShift';
  185. // import processSubmitDialog from '@/components/processSubmitDialog/processSubmitDialog.vue';
  186. import timeTable from './components/timeTable.vue';
  187. import { solarToLunar } from 'lunar-calendar';
  188. import {
  189. getFactoryarea,
  190. getFactoryworkstation,
  191. listFactoryLineByFactoryId,
  192. listByProductionLineId
  193. } from '@/api/factoryModel';
  194. import searchTable from './components/searchTable.vue';
  195. // import { getteampage } from '@/api/workforceManagement/team.js';
  196. import dayjs from 'dayjs';
  197. export default {
  198. mixins: [tabMixins],
  199. components: {
  200. timeTable,
  201. searchTable
  202. // addOrEditDialog
  203. },
  204. data() {
  205. return {
  206. // 加载状态
  207. loading: false,
  208. delVisible: false,
  209. timeValue: new Date(),
  210. selectedDates: [new Date()],
  211. factoriesList: [],
  212. productionShiftList: [],
  213. productionShift: [],
  214. productionLineList: [],
  215. workStationList: [],
  216. selection: [],
  217. defTime: {
  218. step: '00:01',
  219. start: '00:00',
  220. end: '23:59'
  221. },
  222. form: {
  223. factoriesId: '',
  224. factoriesName: '',
  225. productionLineId: '',
  226. productionLineName: '',
  227. workStationId: '',
  228. workStationName: ''
  229. },
  230. params: {
  231. workStationId: '',
  232. productionLineId: '',
  233. productionShift: ''
  234. },
  235. list: [],
  236. processSubmitDialogFlag: false,
  237. cacheKeyUrl: 'main-productionScheduling-workCalendar-index',
  238. columns: [
  239. {
  240. label: '选择',
  241. width: 45,
  242. type: 'selection',
  243. columnKey: 'selection',
  244. align: 'center',
  245. reserveSelection: true
  246. },
  247. {
  248. minWidth: 150,
  249. prop: 'dayDate',
  250. label: '日期',
  251. align: 'center',
  252. slot: 'code',
  253. showOverflowTooltip: true
  254. },
  255. {
  256. minWidth: 180,
  257. prop: 'productionLineName',
  258. label: '产线名称',
  259. align: 'center',
  260. showOverflowTooltip: true
  261. },
  262. {
  263. minWidth: 180,
  264. prop: 'workCenterName',
  265. label: '工作中心',
  266. align: 'center',
  267. showOverflowTooltip: true
  268. },
  269. {
  270. minWidth: 130,
  271. prop: 'workStationName',
  272. label: '工位名称',
  273. align: 'center',
  274. showOverflowTooltip: true
  275. },
  276. {
  277. minWidth: 180,
  278. prop: 'productionShift',
  279. label: '生产班次',
  280. align: 'center',
  281. showOverflowTooltip: true
  282. },
  283. // {
  284. // width: 60,
  285. // label: '序号',
  286. // type: 'index',
  287. // columnKey: 'index',
  288. // align: 'center'
  289. // },
  290. // {
  291. // minWidth: 150,
  292. // prop: 'dutyName',
  293. // slot: 'dutyName',
  294. // label: '出勤名称',
  295. // align: 'center',
  296. // showOverflowTooltip: true
  297. // },
  298. // {
  299. // minWidth: 120,
  300. // prop: 'timeType',
  301. // slot: 'timeType',
  302. // label: '类型',
  303. // align: 'center',
  304. // showOverflowTooltip: true
  305. // },
  306. // {
  307. // minWidth: 150,
  308. // prop: 'startTime',
  309. // slot: 'startTime',
  310. // label: '开始时间',
  311. // align: 'center',
  312. // showOverflowTooltip: true
  313. // },
  314. // {
  315. // minWidth: 150,
  316. // slot: 'endTime',
  317. // prop: 'endTime',
  318. // label: '结束时间',
  319. // align: 'center',
  320. // showOverflowTooltip: true
  321. // },
  322. {
  323. minWidth: 150,
  324. prop: 'workingHours',
  325. label: '工作总时长(分钟)',
  326. align: 'center',
  327. showOverflowTooltip: true
  328. },
  329. {
  330. minWidth: 150,
  331. prop: 'restTime',
  332. label: '休息时间',
  333. align: 'center',
  334. showOverflowTooltip: true
  335. },
  336. {
  337. columnKey: 'action',
  338. label: '操作',
  339. width: 100,
  340. align: 'center',
  341. resizable: false,
  342. slot: 'action',
  343. showOverflowTooltip: true,
  344. fixed: 'right'
  345. }
  346. // {
  347. // minWidth: 100,
  348. // prop: 'updateUserName',
  349. // label: '设置人',
  350. // align: 'center',
  351. // showOverflowTooltip: true
  352. // },
  353. // {
  354. // minWidth: 100,
  355. // prop: 'updateTime',
  356. // label: '设置时间',
  357. // align: 'center',
  358. // showOverflowTooltip: true
  359. // },
  360. // {
  361. // minWidth: 180,
  362. // prop: 'note',
  363. // slot: 'note',
  364. // label: '备注',
  365. // align: 'center',
  366. // showOverflowTooltip: true
  367. // }
  368. ]
  369. };
  370. },
  371. created() {
  372. this.getFactory();
  373. this.getProductionShift();
  374. this.form.factoriesId = this.$store.state.user.info.factoryId;
  375. if (this.form.factoriesId) {
  376. this.getProductionLine();
  377. }
  378. },
  379. methods: {
  380. edit(row) {
  381. if (row?.id) {
  382. this.$refs.timeTableRef.init([row?.id], 'edit');
  383. } else {
  384. this.$refs.timeTableRef.init(
  385. this.selection.map((item) => item.id),
  386. 'edit'
  387. );
  388. }
  389. },
  390. /* 表格数据源 */
  391. datasource({ page, limit, where, order }) {
  392. if (this.selectedDates.length) {
  393. where.dayDate = this.selectedDates.map(
  394. (item) => item.toISOString().split('T')[0]
  395. );
  396. }
  397. return getTableList({
  398. pageNum: page,
  399. size: limit,
  400. ...where
  401. });
  402. },
  403. async search(where) {
  404. this.$refs.table.reload({ page: 1, where });
  405. },
  406. reset() {
  407. this.form = {
  408. factoriesId: '',
  409. factoriesName: '',
  410. productionLineId: '',
  411. productionLineName: ''
  412. };
  413. },
  414. //获取班次
  415. getProductionShift() {
  416. getProductionShift({
  417. pageNum: 1,
  418. size: 999
  419. }).then((res) => {
  420. this.productionShiftList = res.records;
  421. });
  422. },
  423. handleDateClick(date) {
  424. const dateStr = date.toISOString().split('T')[0];
  425. const index = this.selectedDates.findIndex(
  426. (d) => d.toISOString().split('T')[0] === dateStr
  427. );
  428. if (index === -1) {
  429. this.selectedDates.push(date);
  430. } else {
  431. this.selectedDates.splice(index, 1);
  432. }
  433. },
  434. isSelected(date) {
  435. const dateStr = date.toISOString().split('T')[0];
  436. return this.selectedDates.some(
  437. (d) => d.toISOString().split('T')[0] === dateStr
  438. );
  439. },
  440. formatDate(date) {
  441. return date.toISOString().split('T')[0];
  442. },
  443. removeDate(index) {
  444. this.selectedDates.splice(index, 1);
  445. },
  446. lunarDate(date) {
  447. const lunar = solarToLunar(
  448. date.getFullYear(),
  449. date.getMonth() + 1,
  450. date.getDate()
  451. );
  452. return lunar.lunarDay === 1
  453. ? lunar.lunarMonthName + '月'
  454. : lunar.lunarDayName; // 显示农历(初一显示月份)
  455. },
  456. /* 刷新表格 */
  457. reload(where = {}) {
  458. this.$refs.table.reload({ page: 1, where });
  459. },
  460. /* 获取工厂 */
  461. async getFactory() {
  462. const { list } = await getFactoryarea({
  463. pageNum: 1,
  464. size: 999,
  465. type: 1,
  466. enable: 1
  467. });
  468. this.factoriesList = list || [];
  469. },
  470. /* 获取产线 */
  471. async getProductionLine() {
  472. this.productionLineList = await listFactoryLineByFactoryId([
  473. this.form.factoriesId
  474. ]);
  475. },
  476. /* 获取工位 */
  477. async getFactoryworkstation() {
  478. this.workStationList = await listByProductionLineId(
  479. this.form.productionLineId
  480. );
  481. },
  482. change_factoryId() {
  483. this.form.productionLineId = '';
  484. this.form.productionLineName = '';
  485. this.getProductionLine();
  486. },
  487. change_productionLine(item) {
  488. this.form.workStationId = '';
  489. this.form.workStationName = '';
  490. this.form.productionLineName = item.name;
  491. if (item.productionSchedulingDimension) {
  492. this.getFactoryworkstation();
  493. }
  494. },
  495. //根据排程维度获取初始化列表
  496. async getInitList() {
  497. // productionSchedulingDimension
  498. let productionLineList = this.form.productionLineId
  499. ? this.productionLineList.filter(
  500. (item) => item.id == this.form.productionLineId
  501. )
  502. : this.productionLineList;
  503. let promiseAll = [];
  504. //获取工位
  505. productionLineList
  506. .filter((item) => item.productionSchedulingDimension == 1)
  507. .forEach((item) => {
  508. promiseAll.push(listByProductionLineId(item.id));
  509. });
  510. let workStationList = await Promise.all(promiseAll);
  511. workStationList = workStationList.flat();
  512. if (this.form.workStationId) {
  513. workStationList = workStationList.filter(
  514. (item) => item.id == this.form.workStationId
  515. );
  516. }
  517. return [
  518. ...workStationList.map((item) => {
  519. item.productionLineName = productionLineList.find(
  520. (item2) => item2.id == item.productionLineId
  521. )?.name;
  522. item.workStationName = item.name;
  523. item.workStationId = item.id;
  524. return item;
  525. }),
  526. ...productionLineList
  527. .filter((item) => !item.productionSchedulingDimension)
  528. .map((item) => {
  529. item.productionLineName = item.name;
  530. item.productionLineId = item.id;
  531. return item;
  532. })
  533. ];
  534. },
  535. async selectProductionShiftList() {
  536. if (!this.form.factoriesId) {
  537. return this.$message.error('请选择工厂');
  538. }
  539. if (!this.productionLineList.length) {
  540. return this.$message.error('产线不能为空');
  541. }
  542. if (!this.productionShift.length) {
  543. return this.$message.error('请选择班次');
  544. }
  545. let data = await selectProductionShiftList(this.productionShift);
  546. let list = [];
  547. let initList = await this.getInitList();
  548. initList.forEach((Lineitem) => {
  549. data.forEach((dataItem) => {
  550. list.push({
  551. productionLineName: Lineitem.productionLineName,
  552. productionLineId: Lineitem.productionLineId,
  553. workStationName: Lineitem.workStationName,
  554. workStationId: Lineitem.workStationId,
  555. workCenterName: this.form.workCenterName,
  556. workCenterId: this.form.workCenterId,
  557. factoriesName: this.form.factoriesName,
  558. factoriesId: this.form.factoriesId,
  559. productionShift: dataItem.shiftName,
  560. workingHours: dataItem.totalWorkingMinutes,
  561. restTime: dataItem.restDurationMinutes,
  562. list: dataItem.list.map((item) => {
  563. item.id = '';
  564. return item;
  565. }),
  566. dayDate: ''
  567. });
  568. });
  569. });
  570. this.list = this.selectedDates
  571. .map((date) => {
  572. list.forEach((listItem) => {
  573. listItem.dayDate = dayjs(date).format('YYYY-MM-DD');
  574. listItem.list.forEach((item1) => {
  575. item1.dayDate = listItem.dayDate;
  576. item1.productionLineId = listItem.productionLineId;
  577. item1.productionLineName = listItem.productionLineName;
  578. item1.productionShift = listItem.productionShift;
  579. item1.workCenterId = listItem.workCenterId;
  580. item1.workCenterName = listItem.workCenterName;
  581. item1.workStationId = listItem.workStationId;
  582. item1.workStationName = listItem.workStationName;
  583. item1.factoriesName = this.form.factoriesName;
  584. item1.factoriesId = this.form.factoriesId;
  585. });
  586. });
  587. return JSON.parse(JSON.stringify(list));
  588. })
  589. .flat();
  590. saveOrUpdate(this.list).then((res) => {
  591. this.search({
  592. productionLineId: this.form.productionLineId,
  593. workStationId: this.form.workStationId
  594. });
  595. });
  596. },
  597. save() {}
  598. }
  599. };
  600. </script>
  601. <style lang="scss" scoped>
  602. :deep(.el-link--inner) {
  603. margin-left: 0px !important;
  604. }
  605. .sys-organization-list {
  606. height: calc(100vh - 264px);
  607. box-sizing: border-box;
  608. border-width: 1px;
  609. border-style: solid;
  610. overflow: auto;
  611. }
  612. .sys-organization-list :deep(.el-tree-node__content) {
  613. height: 40px;
  614. & > .el-tree-node__expand-icon {
  615. margin-left: 10px;
  616. }
  617. }
  618. :deep(.el-calendar__body) {
  619. padding: 0;
  620. }
  621. .calendar-day {
  622. height: 100%;
  623. display: flex;
  624. flex-direction: column;
  625. align-items: center;
  626. justify-content: center;
  627. cursor: pointer;
  628. }
  629. .selected-date {
  630. background: rgba($color: #409eff, $alpha: 0.2);
  631. }
  632. .selected-dates {
  633. margin-top: 20px;
  634. }
  635. .calendar-container {
  636. width: 480px;
  637. height: 350px;
  638. }
  639. :deep(.el-calendar-day) {
  640. padding: 0;
  641. height: 40px;
  642. }
  643. :deep(.el-calendar-table)th:nth-last-child(-n + 2) {
  644. color: #f56c6c; /* 深色文字 */
  645. }
  646. :deep(.el-calendar-table)td:nth-last-child(-n + 2) {
  647. .datetext {
  648. color: #f56c6c; /* 深色文字 */
  649. }
  650. }
  651. :deep(.el-calendar-table)td.is-today {
  652. color: #409eff !important; /* 深色文字 */
  653. }
  654. .lunar-date {
  655. font-size: 10px;
  656. }
  657. </style>