index.vue 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264
  1. <template>
  2. <div class="tenant">
  3. <!-- <Banner /> -->
  4. <div class="content">
  5. <byTable :source="sourceList.data" :pagination="sourceList.pagination" :config="config" :loading="loading" highlight-current-row
  6. :selectConfig="selectConfig" :table-events="{
  7. //element talbe事件都能传
  8. select: select,
  9. }" :action-list="[]" @get-list="getList">
  10. <template #arrangedQuantity="{ item }">
  11. <div v-if="Number(item.productionQuantity) > item.arrangedQuantity" style="color: red; font-weight: 700">
  12. {{ item.arrangedQuantity }}
  13. </div>
  14. <div v-else>
  15. {{ item.arrangedQuantity }}
  16. </div>
  17. </template>
  18. <template #isCustomized="{ item }">
  19. <div>
  20. <span style="padding: 4px" :class="[item.isCustomized == 1 ? 'active' : '']">
  21. {{
  22. proxy.dictValueLabel(item.isCustomized, isCustomizedData)
  23. }}</span>
  24. </div>
  25. </template>
  26. <template #work="{ item }">
  27. <div style="width:100%">
  28. <span style="padding: 4px" :class="[item.researchStatus == 1 ? 'activea' : 'disActive']">
  29. 【研】设计
  30. </span>
  31. <span style="padding: 4px;margin-left:8px" :class="[item.researchBomStatus == 1 ? 'activea' : 'disActive']">
  32. 【研】BOM
  33. </span>
  34. <span style="padding: 4px;margin-left:8px" :class="[item.electricianBomStatus == 1 ? 'activea' : 'disActive']">
  35. 【电】BOM
  36. </span>
  37. <span style="padding: 4px" :class="[item.technologyStatus == 1 ? 'activea' : 'disActive']">
  38. 【制】工序
  39. </span>
  40. <span style="padding: 4px;margin-left:8px" :class="[item.bomStatus == 1 ? 'activea' : 'disActive']">
  41. 【制】BOM
  42. </span>
  43. <span style="padding: 4px;margin-left:8px" :class="[item.productionQuantity ? 'activea' : 'disActive']">
  44. 【制】下发
  45. </span>
  46. </div>
  47. </template>
  48. <template #completionRate="{ item }">
  49. <div style="width: 100%">
  50. <el-progress type="circle" :percentage="Number(item.completionRate)" width="60"
  51. :status="Number(item.completionRate) == 100 ? 'success' : ''" />
  52. </div>
  53. </template>
  54. <template #btns="{ item }">
  55. <div style="width: 100%">
  56. <div v-if="props.isShowSelect">
  57. <el-button text type="primary" @click="handleSelectRow(item)">选择</el-button>
  58. </div>
  59. <div v-else>
  60. <!-- 研发 -->
  61. <span v-if="isYanFa">
  62. <el-button text type="primary" @click="handleUploadFile(item, false)" v-if="item.devUserId==userId">
  63. <!-- {{
  64. item.researchStatus ? "查看" : "上传"
  65. }} -->
  66. 设计资料
  67. </el-button>
  68. <el-button text type="primary" v-if="item.devUserId==userId" @click="getDtl(item, item.researchBomStatus ? true : false,'all')">
  69. <!-- {{ item.researchBomStatus ? "查看" : "调整" }} -->
  70. BOM</el-button>
  71. </span>
  72. <!-- 电控 -->
  73. <span v-if="isDianGong">
  74. <el-button text type="primary" v-if="item.researchStatus && item.researchBomStatus"
  75. @click="getDtl(item, item.electricianBomStatus ? true : false,2)">
  76. <!-- {{ item.electricianBomStatus ? "查看" : "调整" }} -->
  77. BOM</el-button>
  78. </span>
  79. <!-- 制图 -->
  80. <span v-if="isZhiTu && item.researchStatus && item.researchBomStatus">
  81. <span v-if="item.isCustomized == 1">
  82. <el-button text type="primary" @click="getDtl(item, item.bomStatus ? true : false,1)">
  83. <!-- {{ item.bomStatus ? "查看" : "调整" }} -->
  84. BOM</el-button>
  85. </span>
  86. <span v-if="item.isCustomized == 1">
  87. <el-button text type="primary" @click="
  88. getDtlOne(item, item.technologyStatus ? true : false)
  89. ">
  90. <!-- {{
  91. item.technologyStatus ? "查看" : "调整"
  92. }} -->
  93. 工艺</el-button>
  94. </span>
  95. <span>
  96. <el-button text type="primary" @click="handleUploadFile(item, true)">设计资料</el-button>
  97. </span>
  98. <span v-if="item.isCustomized == 0">
  99. <span v-if="item.productionQuantity == null">
  100. <el-button text type="primary" @click="handleOut(item)">下发</el-button>
  101. </span>
  102. </span>
  103. </span>
  104. <span>
  105. <el-button text type="primary" @click="handlePrint(item)">打印</el-button>
  106. </span>
  107. </div>
  108. </div>
  109. </template>
  110. </byTable>
  111. </div>
  112. <!-- 研发调整bom -->
  113. <el-dialog :title="!isDetail ? '调整BOM' : '查看BOM'" v-model="dialogVisible" width="90%" v-loading="submitLoading" destroy-on-close>
  114. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="byform">
  115. <template #slot>
  116. <div style="width: 100%;display:flex">
  117. <div style="padding-right:10px" v-if="submitType==1 || submitType=='all'" :style="{ width: submitType=='all' ? '50%' : '100%' }">
  118. <div style="color: red; font-size: 14px">
  119. 注意:这是单个产品的物料
  120. </div>
  121. <el-button type="primary" plain @click="clickSelect(1)">添加物料/半成品(五金)</el-button>
  122. <el-table :data="formData.data.workOrderBomList" style="margin-top:15px">
  123. <el-table-column prop="productCode" label="物料编码" />
  124. <el-table-column prop="productName" label="物料名称" />
  125. <el-table-column prop="productSpec" label="规格型号" />
  126. <el-table-column prop="productUnit" label="单位" :formatter="
  127. (row) => dictValueLabel(row.productUnit, materialUnit)
  128. " />
  129. <el-table-column prop="quantity" label="数量" width="150">
  130. <template #default="{ row, $index }">
  131. <el-form-item :prop="'workOrderBomList.' + $index + '.quantity'" :rules="rules.quantity" :inline-message="true">
  132. <el-input-number v-model="row.quantity" :precision="2" :controls="false" :min="1" />
  133. </el-form-item>
  134. </template>
  135. </el-table-column>
  136. <el-table-column prop="zip" label="操作" width="100">
  137. <template #default="{ $index }">
  138. <el-button type="primary" link @click="handleRemove($index,1)">删除</el-button>
  139. </template>
  140. </el-table-column>
  141. </el-table>
  142. </div>
  143. <div style="padding-left:10px" v-if="submitType==2 || submitType=='all'" :style="{ width: submitType=='all' ? '50%' : '100%' }">
  144. <div style="color: red; font-size: 14px">
  145. 注意:这是单个产品的物料
  146. </div>
  147. <el-button type="primary" plain @click="clickSelect(2)">添加物料/半成品(电控)</el-button>
  148. <el-table :data="formData.data.workOrderBomListOne" style="margin-top:15px">
  149. <el-table-column prop="productCode" label="物料编码" />
  150. <el-table-column prop="productName" label="物料名称" />
  151. <el-table-column prop="productSpec" label="规格型号" />
  152. <el-table-column prop="productUnit" label="单位" :formatter="
  153. (row) => dictValueLabel(row.productUnit, materialUnit)
  154. " />
  155. <el-table-column prop="quantity" label="数量" width="150">
  156. <template #default="{ row, $index }">
  157. <el-form-item :prop="'workOrderBomListOne.' + $index + '.quantity'" :rules="rules.quantity" :inline-message="true">
  158. <el-input-number v-model="row.quantity" :precision="2" :controls="false" :min="1" />
  159. </el-form-item>
  160. </template>
  161. </el-table-column>
  162. <el-table-column prop="zip" label="操作" width="100">
  163. <template #default="{ $index }">
  164. <el-button type="primary" link @click="handleRemove($index,2)">删除</el-button>
  165. </template>
  166. </el-table-column>
  167. </el-table>
  168. </div>
  169. </div>
  170. </template>
  171. </byForm>
  172. <template #footer>
  173. <el-button @click="dialogVisible = false" size="large">取 消</el-button>
  174. <el-button type="primary" @click="submitForm(0)" size="large" :loading="submitLoading">
  175. 保 存
  176. </el-button>
  177. <el-button type="primary" @click="submitForm(1)" size="large" :loading="submitLoading" v-if="!isDetail">
  178. 提 交
  179. </el-button>
  180. </template>
  181. </el-dialog>
  182. <el-dialog :title="!isDetailOne ? '调整工艺' : '查看工艺'" v-model="dialogVisibleOne" width="90%" v-loading="loadingOne" destroy-on-close>
  183. <byForm :formConfig="formConfigOne" :formOption="formOptionOne" v-model="formData.dataOne" :rules="rulesOne" ref="byformOne">
  184. <template #lineSlot>
  185. <div class="processChart" style="width:100%">
  186. <div class="from">
  187. <div class="commons-title">工序</div>
  188. <!-- <div>
  189. <el-form labelPosition='top'>
  190. <el-form-item label="工序" label-width="80px">
  191. </el-form-item>
  192. </el-form>
  193. </div> -->
  194. </div>
  195. <div class="content">
  196. <div class="commons-title">工艺路线</div>
  197. <div class="chart-warp">
  198. <vueFlow :nodeObject="nodeObject" ref="vueFlowDom" @addRow="clickAdd" @changeName="changeName" @removeRow="removeRow"></vueFlow>
  199. </div>
  200. </div>
  201. </div>
  202. </template>
  203. <template #slot>
  204. <div style="width: 100%" class="tableDrop">
  205. <!-- <el-button type="primary" plain @click="clickAdd">添加工序</el-button> -->
  206. <el-table :data="formData.dataOne.workOrderProductionProcessesList" style="width: 100%; margin-top: 16px" row-key="id">
  207. <el-table-column label="工序名称" width="150">
  208. <template #default="{ row, $index }">
  209. <div style="width: 100%">
  210. <el-form-item :prop="
  211. 'workOrderProductionProcessesList.' + $index + '.name'
  212. " :rules="rulesOne.name" :inline-message="true">
  213. <el-input v-model="row.name" placeholder="请输入" disabled />
  214. </el-form-item>
  215. </div>
  216. </template>
  217. </el-table-column>
  218. <el-table-column label="工艺说明" width="300">
  219. <template #default="{ row, $index }">
  220. <div style="width: 100%">
  221. <el-form-item :prop="
  222. 'workOrderProductionProcessesList.' +
  223. $index +
  224. '.remarks'
  225. " :rules="rulesOne.remarks" :inline-message="true">
  226. <el-input v-model="row.remarks" type="textarea" placeholder="请输入" />
  227. </el-form-item>
  228. </div>
  229. </template>
  230. </el-table-column>
  231. <el-table-column label="图纸">
  232. <template #default="{ row, $index }">
  233. <div style="width: 100%">
  234. <el-form-item :prop="
  235. 'workOrderProductionProcessesList.' + $index + '.name'
  236. " :rules="rulesOne.name" :inline-message="true">
  237. <el-upload v-model:fileList="row.fileList" :show-file-list="false" class="upload-demo"
  238. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com" :data="uploadData" :before-upload="
  239. (file) => handleBeforeUpload(file, $index)
  240. ">
  241. <el-icon :size="17" style="margin-top: 12px; cursor: pointer">
  242. <Plus />
  243. </el-icon>
  244. </el-upload>
  245. <div v-if="row.fileListCopy && row.fileListCopy.length > 0">
  246. <el-tag style="margin-left: 10px" class="ml-2" type="info" v-for="(item, index) in row.fileListCopy"
  247. :key="index">{{ item.fileName }}</el-tag>
  248. </div>
  249. </el-form-item>
  250. </div>
  251. </template>
  252. </el-table-column>
  253. <!-- <el-table-column align="center" label="操作" width="60" fixed="right">
  254. <template #default="{ $index }">
  255. <el-button type="primary" link @click="clickDelete($index)">删除</el-button>
  256. </template>
  257. </el-table-column> -->
  258. </el-table>
  259. </div>
  260. </template>
  261. <template #file>
  262. <div style="width: 100%">
  263. <el-upload v-model:fileList="formData.dataOne.fileList" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com" :data="uploadData"
  264. multiple :before-upload="handleBeforeUploadOne" :on-success="handleSuccess" :on-preview="onPreviewFile">
  265. <el-button type="primary" plain>选择</el-button>
  266. </el-upload>
  267. </div>
  268. </template>
  269. </byForm>
  270. <template #footer>
  271. <el-button @click="dialogVisibleOne = false" size="large">取 消</el-button>
  272. <el-button type="primary" @click="submitFormOne(0)" size="large" :loading="loadingOne" v-if="!isDetailOne">
  273. 保 存
  274. </el-button>
  275. <el-button type="primary" @click="submitFormOne(1)" size="large" :loading="loadingOne" v-if="!isDetailOne">
  276. 提 交
  277. </el-button>
  278. </template>
  279. </el-dialog>
  280. <el-dialog :title="'工单下发'" v-model="dialogVisibleTwo" width="500" v-loading="submitLoading" destroy-on-close>
  281. <byForm :formConfig="formConfigTwo" :formOption="formOptionTwo" v-model="formData.dataTwo" :rules="rulesTwo" ref="byformTwo">
  282. </byForm>
  283. <template #footer>
  284. <el-button @click="dialogVisibleTwo = false" size="large">取 消</el-button>
  285. <el-button type="primary" @click="submitFormTwo()" size="large" :loading="submitLoading">
  286. 提 交
  287. </el-button>
  288. </template>
  289. </el-dialog>
  290. <el-dialog :title="'上传设计资料'" v-model="informationDialog" width="500" v-loading="submitLoading" destroy-on-close>
  291. <byForm :formConfig="informationFormConfig" :formOption="informationFormOption" v-model="formData.dataThree">
  292. <template #file>
  293. <div style="width: 100%">
  294. <el-upload v-model:fileList="formData.dataThree.fileList" action="https://winfaster.obs.cn-south-1.myhuaweicloud.com" :data="uploadData"
  295. multiple :before-upload="handleBeforeUploadOne" :on-success="handleSuccess" :on-preview="onPreviewFile">
  296. <el-button>选择</el-button>
  297. </el-upload>
  298. </div>
  299. </template>
  300. </byForm>
  301. <template #footer>
  302. <el-button @click="informationDialog = false" size="large">取 消</el-button>
  303. <el-button type="primary" @click="submitInformationForm(0)" size="large" :loading="submitLoading" v-if="!showUploadSubmitOne">
  304. 保 存
  305. </el-button>
  306. <el-button type="primary" @click="submitInformationForm(1)" size="large" :loading="submitLoading"
  307. v-if="!showUploadSubmitOne && !showUploadSubmit">
  308. 提 交
  309. </el-button>
  310. </template>
  311. </el-dialog>
  312. <el-dialog title="打印产品需求单" v-if="printDialog" v-model="printDialog" width="680">
  313. <ProductDemandPDF :rowData="rowData"></ProductDemandPDF>
  314. <template #footer>
  315. <el-button @click="printDialog = false" size="large">取 消</el-button>
  316. <el-button type="primary" v-print="printObj" size="large">打 印</el-button>
  317. </template>
  318. </el-dialog>
  319. <el-dialog v-model="openMaterial" title="选择物料/半成品" width="70%" append-to-body>
  320. <SelectMaterial @handleSelect="handleSelect"></SelectMaterial>
  321. <template #footer>
  322. <span class="dialog-footer">
  323. <el-button @click="openMaterial = false">取消</el-button>
  324. </span>
  325. </template>
  326. </el-dialog>
  327. </div>
  328. </template>
  329. <script setup>
  330. /* eslint-disable vue/no-unused-components */
  331. import { ElMessage, ElMessageBox } from "element-plus";
  332. import byTable from "@/components/byTable/index";
  333. import byForm from "@/components/byForm/index";
  334. import { computed, defineComponent, nextTick, ref } from "vue";
  335. import useUserStore from "@/store/modules/user";
  336. import SelectMaterial from "@/components/product/SelectMaterial";
  337. import Sortable from "sortablejs";
  338. import ProductDemandPDF from "@/components/PDF/productDemandPDF.vue";
  339. import vueFlow from "@/views/JXSK/production/processConfig/vueFlow.vue";
  340. const userInfo = useUserStore();
  341. const userId = computed(() => userInfo.user.userId);
  342. const props = defineProps({
  343. isShowSelect: {
  344. type: Boolean,
  345. default: false,
  346. },
  347. });
  348. const uploadData = ref({});
  349. let fileList = ref([]);
  350. let fileListCopy = ref([]);
  351. const loading = ref(false);
  352. const submitLoading = ref(false);
  353. const loadingOne = ref(false);
  354. const sourceList = ref({
  355. data: [],
  356. pagination: {
  357. total: 3,
  358. pageNum: 1,
  359. pageSize: 10,
  360. },
  361. });
  362. let dialogVisible = ref(false);
  363. let dialogVisibleOne = ref(false);
  364. let openMaterial = ref(false);
  365. let roomDialogVisible = ref(false);
  366. let modalType = ref("add");
  367. let rules = ref({
  368. quantity: [{ required: true, message: "请输入数量", trigger: "blur" }],
  369. });
  370. let rulesOne = ref({
  371. name: [{ required: true, message: "请输入工序名称", trigger: "blur" }],
  372. remarks: [{ required: true, message: "请输入工艺说明", trigger: "blur" }],
  373. });
  374. let rulesTwo = ref({
  375. stockWaitQuantity: [
  376. { required: true, message: "请输入出库数量", trigger: "blur" },
  377. ],
  378. productionQuantity: [
  379. { required: true, message: "请输入生产数量", trigger: "blur" },
  380. ],
  381. });
  382. const { proxy } = getCurrentInstance();
  383. const materialUnit = ref([]);
  384. const workOrderSource = ref([]);
  385. const isCustomizedData = ref([
  386. {
  387. label: "是",
  388. value: "1",
  389. },
  390. {
  391. label: "否",
  392. value: "0",
  393. },
  394. ]);
  395. const isComplete = ref([
  396. {
  397. label: "已处理",
  398. value: "1",
  399. },
  400. {
  401. label: "未处理",
  402. value: "0",
  403. },
  404. ]);
  405. const selectConfig = computed(() => [
  406. // {
  407. // label: "工单来源",
  408. // prop: "source",
  409. // data: workOrderSource.value,
  410. // },
  411. {
  412. label: "是否定制",
  413. prop: "isCustomized",
  414. data: isCustomizedData.value,
  415. },
  416. {
  417. label: "处理状态",
  418. prop: "isComplete",
  419. data: isComplete.value,
  420. },
  421. ]);
  422. const config = computed(() => {
  423. return [
  424. // {
  425. // attrs: {
  426. // label: "工单来源",
  427. // prop: "source",
  428. // width: 100,
  429. // },
  430. // render(source) {
  431. // return proxy.dictValueLabel(source, workOrderSource.value);
  432. // },
  433. // },
  434. {
  435. attrs: {
  436. label: "销售单号",
  437. prop: "contractCode",
  438. width: 110,
  439. },
  440. },
  441. {
  442. attrs: {
  443. label: "合同创建时间",
  444. prop: "contractCreateTime",
  445. width: 160,
  446. },
  447. },
  448. {
  449. attrs: {
  450. label: "工单单号",
  451. prop: "code",
  452. width: 110,
  453. },
  454. },
  455. {
  456. attrs: {
  457. label: "产品名称",
  458. prop: "productName",
  459. "min-width": 220,
  460. },
  461. },
  462. {
  463. attrs: {
  464. label: "产品型号",
  465. prop: "productSpec",
  466. width: 100,
  467. },
  468. },
  469. {
  470. attrs: {
  471. label: "是否定制",
  472. slot: "isCustomized",
  473. width: 80,
  474. },
  475. // render(isCustomized) {
  476. // return isCustomized == 1 ? "是" : "否";
  477. // },
  478. },
  479. {
  480. attrs: {
  481. label: "工单数量",
  482. prop: "quantity",
  483. width: 100,
  484. },
  485. },
  486. {
  487. attrs: {
  488. label: "计划出库数量",
  489. prop: "stockWaitQuantity",
  490. width: 120,
  491. },
  492. },
  493. {
  494. attrs: {
  495. label: "计划生产数量",
  496. prop: "productionQuantity",
  497. width: 120,
  498. },
  499. },
  500. {
  501. attrs: {
  502. type: "slot",
  503. label: "已计划数量",
  504. slot: "arrangedQuantity",
  505. width: 120,
  506. },
  507. },
  508. {
  509. attrs: {
  510. type: "slot",
  511. label: "工作",
  512. slot: "work",
  513. width: 300,
  514. fixed: "right",
  515. },
  516. },
  517. {
  518. attrs: {
  519. label: "完成率",
  520. slot: "completionRate",
  521. width: 120,
  522. align: "center",
  523. fixed: "right",
  524. },
  525. // render(completionRate) {
  526. // if (completionRate !== undefined && completionRate !== "") {
  527. // return completionRate + "%";
  528. // }
  529. // },
  530. },
  531. {
  532. attrs: {
  533. label: "操作",
  534. slot: "btns",
  535. width: "220",
  536. align: "center",
  537. fixed: "right",
  538. },
  539. },
  540. ];
  541. });
  542. let formData = reactive({
  543. data: {},
  544. dataOne: {},
  545. dataTwo: {},
  546. treeData: [],
  547. });
  548. const formOption = reactive({
  549. inline: true,
  550. labelWidth: 100,
  551. itemWidth: 100,
  552. rules: [],
  553. disabled: false,
  554. });
  555. const formOptionOne = reactive({
  556. inline: true,
  557. labelWidth: 100,
  558. itemWidth: 100,
  559. rules: [],
  560. disabled: false,
  561. });
  562. const formOptionTwo = reactive({
  563. inline: true,
  564. labelWidth: 100,
  565. itemWidth: 100,
  566. rules: [],
  567. disabled: false,
  568. });
  569. const informationFormOption = reactive({
  570. inline: true,
  571. labelWidth: 100,
  572. itemWidth: 100,
  573. rules: [],
  574. disabled: false,
  575. });
  576. const byform = ref(null);
  577. const byformOne = ref(null);
  578. const treeData = ref([]);
  579. const formConfig = reactive([
  580. {
  581. type: "slot",
  582. slotName: "slot",
  583. },
  584. ]);
  585. const formConfigOne = reactive([
  586. {
  587. type: "slot",
  588. slotName: "lineSlot",
  589. label: "",
  590. },
  591. {
  592. type: "slot",
  593. slotName: "slot",
  594. label: "",
  595. },
  596. {
  597. type: "slot",
  598. slotName: "file",
  599. label: "上传附件",
  600. },
  601. ]);
  602. const formConfigTwo = reactive([
  603. {
  604. type: "input",
  605. label: "产品名称",
  606. prop: "productName",
  607. disabled: true,
  608. },
  609. {
  610. type: "input",
  611. label: "工单数量",
  612. prop: "orderQuantity",
  613. disabled: true,
  614. itemWidth: 51,
  615. },
  616. {
  617. type: "input",
  618. label: "库存数量",
  619. prop: "availableStockQuantity",
  620. disabled: true,
  621. itemWidth: 51,
  622. },
  623. {
  624. type: "number",
  625. prop: "stockWaitQuantity",
  626. label: "出库数量",
  627. itemWidth: 51,
  628. precision: 0,
  629. min: 0,
  630. controls: false,
  631. style: {
  632. width: "100%",
  633. },
  634. },
  635. {
  636. type: "number",
  637. prop: "productionQuantity",
  638. label: "生产数量",
  639. itemWidth: 51,
  640. precision: 0,
  641. min: 0,
  642. controls: false,
  643. style: {
  644. width: "100%",
  645. },
  646. },
  647. ]);
  648. const informationFormConfig = reactive([
  649. {
  650. type: "slot",
  651. slotName: "file",
  652. label: "上传设计资料",
  653. },
  654. ]);
  655. const getList = async (req) => {
  656. sourceList.value.pagination = { ...sourceList.value.pagination, ...req };
  657. loading.value = true;
  658. proxy
  659. .post("/workOrder/pageByJxst", sourceList.value.pagination)
  660. .then((message) => {
  661. sourceList.value.data = message.rows;
  662. sourceList.value.pagination.total = message.total;
  663. setTimeout(() => {
  664. loading.value = false;
  665. }, 200);
  666. });
  667. };
  668. const openModal = () => {
  669. dialogVisible.value = true;
  670. modalType.value = "add";
  671. formData.data = {};
  672. };
  673. const submitForm = (flag) => {
  674. byform.value.handleSubmit((valid) => {
  675. let type = "";
  676. if (submitType.value == 1) {
  677. type = 1;
  678. } else if (submitType.value == 2) {
  679. type = 2;
  680. }
  681. formData.data.type = type;
  682. if (flag == 1) {
  683. ElMessageBox.confirm(`你确定提交吗?`, "提示", {
  684. confirmButtonText: "确定",
  685. cancelButtonText: "取消",
  686. type: "warning",
  687. }).then(() => {
  688. submitLoading.value = true;
  689. if (submitType.value == 1) {
  690. formData.data.bomStatus = 1;
  691. } else if (submitType.value == 2) {
  692. formData.data.electricianBomStatus = 1;
  693. } else {
  694. formData.data.researchBomStatus = 1;
  695. }
  696. const arr = [
  697. ...formData.data.workOrderBomList,
  698. ...formData.data.workOrderBomListOne,
  699. ];
  700. // formData.data.workOrderBomList = arr;
  701. proxy
  702. .post("/workOrder/editBom", {
  703. ...formData.data,
  704. workOrderBomList: arr,
  705. })
  706. .then(
  707. (res) => {
  708. ElMessage({
  709. message: "操作成功",
  710. type: "success",
  711. });
  712. dialogVisible.value = false;
  713. submitLoading.value = false;
  714. getList();
  715. },
  716. (err) => (submitLoading.value = false)
  717. );
  718. });
  719. } else {
  720. submitLoading.value = true;
  721. const arr = [
  722. ...formData.data.workOrderBomList,
  723. ...formData.data.workOrderBomListOne,
  724. ];
  725. // formData.data.workOrderBomList = arr;
  726. proxy
  727. .post("/workOrder/editBom", { ...formData.data, workOrderBomList: arr })
  728. .then(
  729. (res) => {
  730. ElMessage({
  731. message: "操作成功",
  732. type: "success",
  733. });
  734. dialogVisible.value = false;
  735. submitLoading.value = false;
  736. getList();
  737. },
  738. (err) => (submitLoading.value = false)
  739. );
  740. }
  741. });
  742. };
  743. const vueFlowDom = ref(null);
  744. const submitApi = (type) => {
  745. const data = vueFlowDom.value.submitAll();
  746. if (!data) {
  747. return;
  748. }
  749. formData.dataOne.customizedNodeObject = data.nodeObject;
  750. formData.dataOne.fileList = formData.dataOne.fileList.map((item) => {
  751. return {
  752. id: item.raw.id,
  753. fileName: item.raw.fileName,
  754. fileUrl: item.raw.fileUrl,
  755. uploadState: item.raw.uploadState,
  756. };
  757. });
  758. for (
  759. let i = 0;
  760. i < formData.dataOne.workOrderProductionProcessesList.length;
  761. i++
  762. ) {
  763. const e = formData.dataOne.workOrderProductionProcessesList[i];
  764. e.fileList = e.fileListCopy;
  765. }
  766. formData.dataOne.technologyStatus = type;
  767. loadingOne.value = true;
  768. proxy.post("/workOrderProductionProcesses/edit", formData.dataOne).then(
  769. (res) => {
  770. ElMessage({
  771. message: "操作成功",
  772. type: "success",
  773. });
  774. dialogVisibleOne.value = false;
  775. loadingOne.value = false;
  776. getList();
  777. },
  778. (err) => (loadingOne.value = false)
  779. );
  780. };
  781. const submitFormOne = (type) => {
  782. byformOne.value.handleSubmit((valid) => {
  783. // for (
  784. // let i = 0;
  785. // i < formData.dataOne.workOrderProductionProcessesList.length;
  786. // i++
  787. // ) {
  788. // const e = formData.dataOne.workOrderProductionProcessesList[i];
  789. // if (!e.fileListCopy.length > 0) {
  790. // return ElMessage({
  791. // message: "请上传图纸",
  792. // type: "info",
  793. // });
  794. // }
  795. // }
  796. if (type) {
  797. ElMessageBox.confirm(`你确定提交吗?`, "提示", {
  798. confirmButtonText: "确定",
  799. cancelButtonText: "取消",
  800. type: "warning",
  801. }).then(() => {
  802. submitApi(type);
  803. });
  804. } else {
  805. submitApi(type);
  806. }
  807. });
  808. };
  809. const isDetail = ref(false);
  810. const submitType = ref("all");
  811. const getDtl = (row, flag, submit) => {
  812. submitType.value = submit;
  813. isDetail.value = flag;
  814. modalType.value = "edit";
  815. proxy.post("/workOrderBom/list", { workOrderId: row.id }).then((res) => {
  816. // 五金
  817. let workOrderBomList = res.filter((x) => x.type == 1);
  818. let workOrderBomListOne = res.filter((x) => x.type == 2);
  819. formData.data = {
  820. workOrderBomList: workOrderBomList || [],
  821. workOrderBomListOne: workOrderBomListOne || [],
  822. workOrderId: row.id,
  823. };
  824. dialogVisible.value = true;
  825. });
  826. };
  827. const handleRemove = (index, type) => {
  828. if (type == 1) {
  829. formData.data.workOrderBomList.splice(index, 1);
  830. } else {
  831. formData.data.workOrderBomListOne.splice(index, 1);
  832. }
  833. };
  834. // 对el-table进行拖拽排序
  835. const initSort = () => {
  836. const tbody = document.querySelector(
  837. ".tableDrop .el-table__body-wrapper tbody"
  838. );
  839. Sortable.create(tbody, {
  840. onEnd({ newIndex, oldIndex }) {
  841. if (newIndex == oldIndex) return;
  842. formData.dataOne.workOrderProductionProcessesList.splice(
  843. newIndex,
  844. 0,
  845. formData.dataOne.workOrderProductionProcessesList.splice(oldIndex, 1)[0]
  846. );
  847. var newArray = formData.dataOne.workOrderProductionProcessesList.slice(0);
  848. formData.dataOne.workOrderProductionProcessesList = [];
  849. nextTick(() => {
  850. formData.dataOne.workOrderProductionProcessesList = newArray;
  851. });
  852. },
  853. });
  854. };
  855. const isDetailOne = ref(false);
  856. const nodeObject = ref("");
  857. const getDtlOne = (row, flag) => {
  858. isDetailOne.value = flag;
  859. // formOptionOne.disabled = flag;
  860. formOptionOne.disabled = false;
  861. modalType.value = "edit";
  862. proxy
  863. .post("/workOrderProductionProcesses/detail", { workOrderId: row.id })
  864. .then((res) => {
  865. nodeObject.value = res.customizedNodeObject;
  866. dialogVisibleOne.value = true;
  867. res.workOrderProductionProcessesList =
  868. res.workOrderProductionProcessesList.map((x) => {
  869. if (x.fileList && x.fileList.length > 0) {
  870. x.fileListCopy = x.fileList.map((x) => ({ ...x }));
  871. } else {
  872. x.fileList = [];
  873. }
  874. return x;
  875. });
  876. formData.dataOne = {
  877. workOrderId: row.id,
  878. workOrderProductionProcessesList: res.workOrderProductionProcessesList,
  879. fileList: [],
  880. };
  881. // nextTick(() => {
  882. // initSort();
  883. // });
  884. proxy
  885. .post("/fileInfo/getList", { businessIdList: [row.id], fileType: 1 })
  886. .then((fileObj) => {
  887. if (fileObj[row.id] && fileObj[row.id].length > 0) {
  888. formData.dataOne.fileList = fileObj[row.id].map((item) => {
  889. return {
  890. raw: item,
  891. name: item.fileName,
  892. url: item.fileUrl,
  893. };
  894. });
  895. }
  896. });
  897. });
  898. };
  899. const getDict = () => {
  900. proxy.getDictOne(["material_unit", "work_order_source"]).then((res) => {
  901. materialUnit.value = res["material_unit"].map((x) => ({
  902. label: x.dictValue,
  903. value: x.dictKey,
  904. }));
  905. workOrderSource.value = res["work_order_source"].map((x) => ({
  906. label: x.dictValue,
  907. value: x.dictKey,
  908. }));
  909. });
  910. };
  911. const isYanFa = ref(false);
  912. const isZhiTu = ref(false);
  913. const isDianGong = ref(false);
  914. const checkShow = () => {
  915. // 当前账号角色是否是研发
  916. if (userInfo.roles.includes("dev")) {
  917. isYanFa.value = true;
  918. }
  919. // 当前角色是否是制图
  920. if (userInfo.roles.includes("design")) {
  921. isZhiTu.value = true;
  922. }
  923. // 当前角色是否是电工
  924. if (userInfo.roles.includes("electrician")) {
  925. isDianGong.value = true;
  926. }
  927. };
  928. checkShow();
  929. getList();
  930. getDict();
  931. const selectType = ref(-1);
  932. const clickSelect = (type) => {
  933. selectType.value = type;
  934. openMaterial.value = true;
  935. };
  936. const handleSelect = (row) => {
  937. if (selectType.value == 1) {
  938. const flag = formData.data.workOrderBomList.some(
  939. (x) => x.productId === row.id
  940. );
  941. if (flag)
  942. return ElMessage({
  943. message: "该物料已选择",
  944. type: "info",
  945. });
  946. formData.data.workOrderBomList.push({
  947. productId: row.id,
  948. productCode: row.code,
  949. productName: row.name,
  950. productSpec: row.spec,
  951. productUnit: row.unit,
  952. quantity: null,
  953. type: "1",
  954. });
  955. } else {
  956. const flag = formData.data.workOrderBomListOne.some(
  957. (x) => x.productId === row.id
  958. );
  959. if (flag)
  960. return ElMessage({
  961. message: "该物料已选择",
  962. type: "info",
  963. });
  964. formData.data.workOrderBomListOne.push({
  965. productId: row.id,
  966. productCode: row.code,
  967. productName: row.name,
  968. productSpec: row.spec,
  969. productUnit: row.unit,
  970. quantity: null,
  971. type: "2",
  972. });
  973. }
  974. return ElMessage({
  975. message: "选择成功",
  976. type: "success",
  977. });
  978. };
  979. const clickAdd = ({ productionId, name }) => {
  980. let obj = {
  981. fileList: [],
  982. fileListCopy: [],
  983. name: "",
  984. remarks: "",
  985. };
  986. if (productionId) {
  987. obj.id = productionId;
  988. }
  989. if (name) {
  990. obj.name = name;
  991. }
  992. formData.dataOne.workOrderProductionProcessesList.push(obj);
  993. };
  994. const removeRow = ({ id }) => {
  995. const index = formData.dataOne.workOrderProductionProcessesList.findIndex(
  996. (x) => x.id == id
  997. );
  998. if (index > -1) {
  999. formData.dataOne.workOrderProductionProcessesList.splice(index, 1);
  1000. }
  1001. };
  1002. const changeName = ({ productionId, name }) => {
  1003. const index = formData.dataOne.workOrderProductionProcessesList.findIndex(
  1004. (x) => x.id == productionId
  1005. );
  1006. if (index > -1) {
  1007. formData.dataOne.workOrderProductionProcessesList[index].name = name;
  1008. }
  1009. };
  1010. const clickDelete = (index) => {
  1011. formData.dataOne.workOrderProductionProcessesList.splice(index, 1);
  1012. };
  1013. const handleBeforeUpload = async (file, index) => {
  1014. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  1015. uploadData.value = res.uploadBody;
  1016. formData.dataOne.workOrderProductionProcessesList[index].fileListCopy = [
  1017. {
  1018. id: res.id,
  1019. fileName: res.fileName,
  1020. path: res.fileUrl,
  1021. url: res.fileUrl,
  1022. uid: file.uid,
  1023. },
  1024. ];
  1025. };
  1026. const handleBeforeUploadOne = async (file) => {
  1027. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  1028. uploadData.value = res.uploadBody;
  1029. file.id = res.id;
  1030. file.fileName = res.fileName;
  1031. file.fileUrl = res.fileUrl;
  1032. file.uploadState = true;
  1033. return true;
  1034. };
  1035. const handleSuccess = (any, UploadFile) => {
  1036. UploadFile.raw.uploadState = false;
  1037. };
  1038. const onPreviewFile = (file) => {
  1039. window.open(file.raw.fileUrl, "_blank");
  1040. };
  1041. const dialogVisibleTwo = ref(false);
  1042. const byformTwo = ref(null);
  1043. const handleOut = (row) => {
  1044. dialogVisibleTwo.value = true;
  1045. proxy.post("/workOrder/detail", { id: row.id }).then((res) => {
  1046. formData.dataTwo = {
  1047. id: row.id,
  1048. productName: row.productName + `(${row.productSpec})`,
  1049. orderQuantity: row.quantity,
  1050. productionQuantity: res.productionQuantity
  1051. ? res.productionQuantity
  1052. : null,
  1053. availableStockQuantity: res.availableStockQuantity,
  1054. };
  1055. });
  1056. };
  1057. const submitFormTwo = (type) => {
  1058. byformTwo.value.handleSubmit((valid) => {
  1059. if (
  1060. formData.dataTwo.productionQuantity +
  1061. formData.dataTwo.stockWaitQuantity !=
  1062. Number(formData.dataTwo.orderQuantity)
  1063. ) {
  1064. return ElMessage({
  1065. message: "出库数量和生产数量合必须等于工单数量",
  1066. type: "info",
  1067. });
  1068. }
  1069. if (
  1070. formData.dataTwo.stockWaitQuantity >
  1071. Number(formData.dataTwo.availableStockQuantity)
  1072. ) {
  1073. return ElMessage({
  1074. message: "出库数量不可大于库存数量",
  1075. type: "info",
  1076. });
  1077. }
  1078. submitLoading.value = true;
  1079. proxy.post("/workOrder/distribute", formData.dataTwo).then(
  1080. (res) => {
  1081. ElMessage({
  1082. message: "操作成功",
  1083. type: "success",
  1084. });
  1085. dialogVisibleTwo.value = false;
  1086. submitLoading.value = false;
  1087. getList();
  1088. },
  1089. (err) => (submitLoading.value = false)
  1090. );
  1091. });
  1092. };
  1093. const informationDialog = ref(false);
  1094. const showUploadSubmit = ref(false);
  1095. const showUploadSubmitOne = ref(false);
  1096. const handleUploadFile = (row, flag) => {
  1097. showUploadSubmit.value = row.researchStatus == 1 ? true : false;
  1098. showUploadSubmitOne.value = flag;
  1099. formData.dataThree = {
  1100. id: row.id,
  1101. fileList: [],
  1102. };
  1103. informationDialog.value = true;
  1104. proxy
  1105. .post("/fileInfo/getList", {
  1106. businessIdList: [row.id],
  1107. fileType: 0,
  1108. })
  1109. .then((res) => {
  1110. if (res[row.id] && res[row.id].length > 0) {
  1111. formData.dataThree.fileList = res[row.id].map((item) => {
  1112. return {
  1113. raw: item,
  1114. name: item.fileName,
  1115. url: item.fileUrl,
  1116. };
  1117. });
  1118. }
  1119. });
  1120. };
  1121. const submitInformationForm = (type) => {
  1122. if (formData.dataThree.fileList && formData.dataThree.fileList.length > 0) {
  1123. formData.dataThree.fileList = formData.dataThree.fileList.map((x) => x.raw);
  1124. formData.dataThree.researchStatus = type == 1 ? "1" : "";
  1125. submitLoading.value = true;
  1126. proxy.post("/workOrder/research", formData.dataThree).then(
  1127. (res) => {
  1128. ElMessage({
  1129. message: "操作成功",
  1130. type: "success",
  1131. });
  1132. informationDialog.value = false;
  1133. submitLoading.value = false;
  1134. getList();
  1135. },
  1136. (err) => (submitLoading.value = false)
  1137. );
  1138. } else {
  1139. return ElMessage({
  1140. message: "请上传设计资料",
  1141. type: "info",
  1142. });
  1143. }
  1144. };
  1145. const printDialog = ref(false);
  1146. const rowData = ref({});
  1147. const handlePrint = (row) => {
  1148. rowData.value = {
  1149. id: row.id,
  1150. };
  1151. printDialog.value = true;
  1152. };
  1153. const printObj = ref({
  1154. id: "pdfDom",
  1155. popTitle: "",
  1156. extraCss:
  1157. "https://cdn.bootcdn.net/ajax/libs/animate.css/4.1.1/animate.compat.css, https://cdn.bootcdn.net/ajax/libs/hover.css/2.3.1/css/hover-min.css",
  1158. extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>',
  1159. });
  1160. const handleSelectRow = (row) => {
  1161. proxy.$emit("handleSelectRow", row);
  1162. };
  1163. </script>
  1164. <style lang="scss" scoped>
  1165. .tenant {
  1166. padding: 20px;
  1167. }
  1168. ::v-deep(.el-input-number .el-input__inner) {
  1169. text-align: left;
  1170. }
  1171. ::v-deep(.el-progress__text) {
  1172. font-size: 15px !important;
  1173. }
  1174. .active {
  1175. background: #98db6b;
  1176. color: #fff;
  1177. border-radius: 4px;
  1178. }
  1179. .activea {
  1180. background: #98db6b;
  1181. color: #fff;
  1182. border-radius: 4px;
  1183. border: 1px solid #98db6b;
  1184. }
  1185. .disActive {
  1186. // background: #fa9841;
  1187. // background: #c4c4c4;
  1188. // border: 1px solid #1c1b1b;
  1189. border-radius: 4px;
  1190. // color: #1c1b1b;
  1191. border: 1px solid #c4c4c4;
  1192. color: #c4c4c4;
  1193. }
  1194. .processChart {
  1195. border: 1px solid #ccc;
  1196. padding: 20px;
  1197. display: flex;
  1198. justify-content: space-between;
  1199. position: relative;
  1200. .from {
  1201. width: 400px;
  1202. background: #fff;
  1203. border-radius: 5px;
  1204. padding: 20px;
  1205. }
  1206. .content {
  1207. width: calc(100% - 420px);
  1208. border-radius: 5px;
  1209. padding: 20px;
  1210. background: #fff;
  1211. }
  1212. }
  1213. .chart-warp {
  1214. width: 100%;
  1215. // height: calc(100vh - 280px);
  1216. }
  1217. </style>