index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. <template>
  2. <div class="tenant">
  3. <div class="content">
  4. <byTable
  5. :source="sourceList.data"
  6. :pagination="sourceList.pagination"
  7. :config="config"
  8. :loading="loading"
  9. highlight-current-row
  10. :selectConfig="selectConfig"
  11. :table-events="{
  12. select: select,
  13. }"
  14. :action-list="[
  15. {
  16. text: '添加任务',
  17. action: () => openModal('add'),
  18. },
  19. ]"
  20. @get-list="getList"
  21. >
  22. </byTable>
  23. </div>
  24. <el-dialog
  25. :title="modalType == 'add' ? '添加任务' : '查看任务'"
  26. v-model="dialogVisible"
  27. width="700"
  28. v-loading="loading"
  29. destroy-on-close
  30. :before-close="handleClose"
  31. >
  32. <byForm
  33. :formConfig="formConfig"
  34. :formOption="formOption"
  35. v-model="formData.data"
  36. :rules="rules"
  37. ref="byform"
  38. v-if="modalType == 'add'"
  39. >
  40. <template
  41. v-for="(cur, index) in productionProcessesList"
  42. :key="cur.id"
  43. v-slot:[cur.id]="{ item }"
  44. >
  45. <el-select
  46. v-model="productionObj[cur.id]"
  47. multiple
  48. placeholder="请选择负责人"
  49. >
  50. <el-option
  51. v-for="item in userList"
  52. :key="item.value"
  53. :label="item.label"
  54. :value="item.value"
  55. />
  56. </el-select>
  57. </template>
  58. </byForm>
  59. <byForm
  60. :formConfig="formConfigOne"
  61. :formOption="formOptionOne"
  62. v-model="formData.dataOne"
  63. ref="byformOne"
  64. v-else
  65. >
  66. <template #list>
  67. <div style="width: 100%">
  68. <el-table :data="formData.dataOne.productionTaskDetailList">
  69. <el-table-column prop="productSn" label="产品SN" />
  70. <el-table-column
  71. prop="productionProcessesName"
  72. label="当前工序"
  73. />
  74. <el-table-column prop="cumulativeTime" label="累计耗时" />
  75. <el-table-column
  76. label="工序状态"
  77. prop="processesStatus"
  78. :formatter="
  79. (row) =>
  80. dictValueLabel(row.processesStatus, processesStatusData)
  81. "
  82. />
  83. </el-table>
  84. </div>
  85. </template>
  86. </byForm>
  87. <template #footer>
  88. <el-button @click="handleClose" size="large">取 消</el-button>
  89. <el-button
  90. type="primary"
  91. @click="submitForm()"
  92. size="large"
  93. :loading="submitLoading"
  94. v-if="modalType == 'add'"
  95. >
  96. 确 定
  97. </el-button>
  98. </template>
  99. </el-dialog>
  100. </div>
  101. </template>
  102. <script setup>
  103. import { ElMessage, ElMessageBox } from "element-plus";
  104. import byTable from "@/components/byTable/index";
  105. import byForm from "@/components/byForm/index";
  106. import useUserStore from "@/store/modules/user";
  107. const { proxy } = getCurrentInstance();
  108. const loading = ref(false);
  109. const submitLoading = ref(false);
  110. const sourceList = ref({
  111. data: [],
  112. pagination: {
  113. total: 3,
  114. pageNum: 1,
  115. pageSize: 10,
  116. keyword: "",
  117. },
  118. });
  119. const processesStatusData = ref([
  120. {
  121. label: "未开始",
  122. value: "0",
  123. },
  124. {
  125. label: "进行中",
  126. value: "1",
  127. },
  128. {
  129. label: "驳回",
  130. value: "2",
  131. },
  132. {
  133. label: "完成",
  134. value: "3",
  135. },
  136. ]);
  137. const dialogVisible = ref(false);
  138. const modalType = ref("add");
  139. const rules = ref({
  140. productionPlanId: [
  141. { required: true, message: "请选择生产计划", trigger: "change" },
  142. ],
  143. dueDate: [{ required: true, message: "请选择完成期限", trigger: "change" }],
  144. quantity: [{ required: true, message: "请输入生产数量", trigger: "blur" }],
  145. });
  146. const selectConfig = reactive([]);
  147. const config = computed(() => {
  148. return [
  149. {
  150. attrs: {
  151. label: "计划单号",
  152. prop: "productionPlanCode",
  153. },
  154. },
  155. {
  156. attrs: {
  157. label: "任务编码",
  158. prop: "code",
  159. },
  160. },
  161. {
  162. attrs: {
  163. label: "产品名称",
  164. prop: "productName",
  165. },
  166. },
  167. {
  168. attrs: {
  169. label: "任务数量",
  170. prop: "quantity",
  171. },
  172. },
  173. {
  174. attrs: {
  175. label: "完成期限",
  176. prop: "dueDate",
  177. },
  178. },
  179. {
  180. attrs: {
  181. label: "操作",
  182. width: "80",
  183. align: "center",
  184. },
  185. renderHTML(row) {
  186. return [
  187. {
  188. attrs: {
  189. label: "查看",
  190. type: "primary",
  191. text: true,
  192. },
  193. el: "button",
  194. click() {
  195. getDtl(row);
  196. },
  197. },
  198. ];
  199. },
  200. },
  201. ];
  202. });
  203. const formData = reactive({
  204. data: {},
  205. dataOne: {},
  206. });
  207. const formOption = reactive({
  208. inline: true,
  209. labelWidth: 100,
  210. itemWidth: 100,
  211. rules: [],
  212. });
  213. const formOptionOne = reactive({
  214. inline: true,
  215. labelWidth: 100,
  216. itemWidth: 100,
  217. rules: [],
  218. });
  219. const byform = ref(null);
  220. const formConfig = computed(() => {
  221. return [
  222. {
  223. type: "select",
  224. prop: "productionPlanId",
  225. label: "生产计划",
  226. required: true,
  227. filterable: true,
  228. data: planData.value,
  229. fn: (val) => {
  230. changeFn(val);
  231. },
  232. style: {
  233. width: "50%",
  234. },
  235. },
  236. {
  237. type: "input",
  238. itemType: "text",
  239. prop: "productName",
  240. label: "产品名称",
  241. disabled: true,
  242. style: {
  243. width: "50%",
  244. },
  245. },
  246. {
  247. type: "input",
  248. itemType: "text",
  249. prop: "waitQuantity",
  250. label: "待排程数量",
  251. disabled: true,
  252. style: {
  253. width: "50%",
  254. },
  255. },
  256. {
  257. type: "number",
  258. prop: "quantity",
  259. label: "任务数量",
  260. precision: 0,
  261. min: 1,
  262. controls: false,
  263. style: {
  264. width: "50%",
  265. },
  266. },
  267. {
  268. type: "date",
  269. itemType: "date",
  270. prop: "dueDate",
  271. label: "完成期限",
  272. required: true,
  273. style: {
  274. width: "50%",
  275. },
  276. },
  277. ];
  278. });
  279. const formConfigOne = computed(() => {
  280. return [
  281. {
  282. type: "select",
  283. prop: "productionPlanId",
  284. label: "生产计划",
  285. required: true,
  286. filterable: true,
  287. data: planDataOne.value,
  288. fn: (val) => {
  289. changeFn(val);
  290. },
  291. style: {
  292. width: "50%",
  293. },
  294. },
  295. {
  296. type: "input",
  297. itemType: "text",
  298. prop: "productName",
  299. label: "产品名称",
  300. disabled: true,
  301. style: {
  302. width: "50%",
  303. },
  304. },
  305. {
  306. type: "input",
  307. itemType: "text",
  308. prop: "waitQuantity",
  309. label: "待排程数量",
  310. disabled: true,
  311. style: {
  312. width: "50%",
  313. },
  314. isShow: modalType.value == "add",
  315. },
  316. {
  317. type: "number",
  318. prop: "quantity",
  319. label: "任务数量",
  320. precision: 0,
  321. min: 1,
  322. controls: false,
  323. style: {
  324. width: "50%",
  325. },
  326. },
  327. {
  328. type: "date",
  329. itemType: "date",
  330. prop: "dueDate",
  331. label: "完成期限",
  332. required: true,
  333. style: {
  334. width: "50%",
  335. },
  336. },
  337. {
  338. type: "slot",
  339. slotName: "list",
  340. label: "产品明细",
  341. },
  342. ];
  343. });
  344. const getList = async (req) => {
  345. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  346. loading.value = true;
  347. proxy
  348. .post("/productionTask/page", sourceList.value.pagination)
  349. .then((message) => {
  350. sourceList.value.data = message.rows;
  351. sourceList.value.pagination.total = message.total;
  352. setTimeout(() => {
  353. loading.value = false;
  354. }, 200);
  355. });
  356. };
  357. const openModal = () => {
  358. dialogVisible.value = true;
  359. modalType.value = "add";
  360. formOption.disabled = false;
  361. formData.data = {};
  362. };
  363. const submitForm = () => {
  364. byform.value.handleSubmit(() => {
  365. if (Number(formData.data.quantity) > Number(formData.data.waitQuantity)) {
  366. return ElMessage({
  367. message: "任务数量不可大于待排程数量",
  368. type: "info",
  369. });
  370. }
  371. // if (proxy.compareTime(formData.data.startDate, formData.data.dueDate)) {
  372. // return ElMessage({
  373. // message: "完成期限不可小于计划开始时间",
  374. // type: "info",
  375. // });
  376. // }
  377. for (const key in productionObj.value) {
  378. if (productionObj.value[key] && productionObj.value[key].length > 0) {
  379. } else {
  380. return ElMessage({
  381. message: "所有工序都需选择负责人!",
  382. type: "info",
  383. });
  384. }
  385. }
  386. formData.data.taskProcessesUser = JSON.stringify(productionObj.value);
  387. submitLoading.value = true;
  388. proxy.post("/productionTask/addByJxst", formData.data).then(
  389. () => {
  390. ElMessage({
  391. message: "添加成功",
  392. type: "success",
  393. });
  394. handleClose();
  395. submitLoading.value = false;
  396. getList();
  397. getDict();
  398. },
  399. (err) => {
  400. console.log(err);
  401. submitLoading.value = false;
  402. }
  403. );
  404. });
  405. };
  406. const getDtl = (row) => {
  407. modalType.value = "detail";
  408. formOptionOne.disabled = true;
  409. proxy.post("/productionTask/detailByJxst", { id: row.id }).then((res) => {
  410. formData.dataOne = res;
  411. formData.dataOne.waitQuantity = res.remainingQuantity;
  412. dialogVisible.value = true;
  413. });
  414. };
  415. const userList = ref([]);
  416. const planData = ref([]);
  417. const planDataOne = ref([]);
  418. const statusData = ref([
  419. {
  420. label: "未开始",
  421. value: "0",
  422. },
  423. {
  424. label: "进行中",
  425. value: "1",
  426. },
  427. {
  428. label: "完成",
  429. value: "2",
  430. },
  431. ]);
  432. const getDict = () => {
  433. proxy
  434. .get("/tenantUser/list", {
  435. pageNum: 1,
  436. pageSize: 10000,
  437. tenantId: useUserStore().user.tenantId,
  438. })
  439. .then((res) => {
  440. userList.value = res.rows.map((item) => {
  441. return {
  442. label: item.nickName,
  443. value: item.userId,
  444. };
  445. });
  446. });
  447. proxy
  448. .post("/productionPlan/page", {
  449. pageNum: 1,
  450. pageSize: 9999,
  451. isRemaining: "1",
  452. })
  453. .then((res) => {
  454. planData.value = res.rows.map((x) => ({
  455. label: x.code + `(${x.startDate}-${x.stopDate})`,
  456. value: x.id,
  457. ...x,
  458. }));
  459. });
  460. proxy
  461. .post("/productionPlan/page", {
  462. pageNum: 1,
  463. pageSize: 9999,
  464. })
  465. .then((res) => {
  466. planDataOne.value = res.rows.map((x) => ({
  467. label: x.code,
  468. value: x.id,
  469. ...x,
  470. }));
  471. });
  472. };
  473. getDict();
  474. getList();
  475. const changeId = ref("");
  476. const changeFn = (val) => {
  477. const current =
  478. modalType.value == "add"
  479. ? planData.value.find((x) => x.value == val)
  480. : planDataOne.value.find((x) => x.value == val);
  481. if (current) {
  482. formData.data.productName = current.productName;
  483. formData.data.waitQuantity = current.remainingQuantity;
  484. }
  485. if (
  486. productionProcessesList.value &&
  487. productionProcessesList.value.length > 0
  488. ) {
  489. // changeId.value = productionProcessesList.value[0].id;
  490. // const index = formConfig.value.findIndex(
  491. // (x) => x.slotName === changeId.value
  492. // );
  493. formConfig.value.splice(5, productionProcessesList.value.length);
  494. productionProcessesList.value = [];
  495. productionObj.value = {};
  496. }
  497. getProductionDetails(val);
  498. };
  499. const productionProcessesList = ref([]);
  500. const productionObj = ref({});
  501. const getProductionDetails = (id) => {
  502. proxy.post("/productionPlan/detail", { id }).then((res) => {
  503. productionProcessesList.value = res.productionProcessesList;
  504. for (let i = 0; i < productionProcessesList.value.length; i++) {
  505. const e = productionProcessesList.value[i];
  506. formConfig.value.push({
  507. type: "slot",
  508. label: e.name + " 负责人",
  509. slotName: e.id,
  510. });
  511. productionObj.value[e.id] = [];
  512. }
  513. });
  514. };
  515. const handleClose = () => {
  516. if (
  517. productionProcessesList.value &&
  518. productionProcessesList.value.length > 0
  519. ) {
  520. formConfig.value.splice(5, productionProcessesList.value.length);
  521. }
  522. productionProcessesList.value = [];
  523. productionObj.value = {};
  524. dialogVisible.value = false;
  525. };
  526. </script>
  527. <style lang="scss" scoped>
  528. .tenant {
  529. padding: 20px;
  530. }
  531. ::v-deep(.el-input-number .el-input__inner) {
  532. text-align: left;
  533. }
  534. </style>