quick.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. <template>
  2. <div>
  3. <el-card class="box-card">
  4. <byForm :formConfig="formConfig" :formOption="formOption" v-model="formData.data" :rules="rules" ref="submit">
  5. <template #basicInformation>
  6. <div style="width: 100%">
  7. <el-row>
  8. <el-col :span="12">
  9. <el-form-item label="事业部" prop="departmentId" style="width: 100%; margin-bottom: 18px">
  10. <el-select v-model="formData.data.departmentId" placeholder="请选择事业部" clearable style="width: 100%" @change="changeDepartment">
  11. <el-option v-for="item in departmentList" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" />
  12. </el-select>
  13. </el-form-item>
  14. <el-form-item label="出库类型" prop="detailType" style="width: 100%; margin-bottom: 18px">
  15. <el-select v-model="formData.data.detailType" placeholder="请选择出库类型" clearable style="width: 100%">
  16. <el-option v-for="item in useUserStore().allDict['come_stock_type']" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" />
  17. </el-select>
  18. </el-form-item>
  19. <el-form-item label="申请人" prop="applicant" style="width: 100%; margin-bottom: 18px">
  20. <el-input v-model="formData.data.applicant" placeholder="请输入申请人" />
  21. </el-form-item>
  22. </el-col>
  23. <el-col :span="12">
  24. <el-form-item label="备注" prop="remark" style="width: 100%; margin-bottom: 18px">
  25. <el-input v-model="formData.data.remark" :rows="4" type="textarea" placeholder="请输入备注" />
  26. </el-form-item>
  27. </el-col>
  28. </el-row>
  29. </div>
  30. </template>
  31. <template #inOutStorageBomList>
  32. <div style="width: 100%; padding: 0 20px">
  33. <el-table :data="formData.data.inOutStorageBomList" :row-style="{ height: '35px' }" header-row-class-name="tableHeader">
  34. <el-table-column type="expand">
  35. <template #default="props">
  36. <div style="padding: 0 80px 0 50px">
  37. <el-table
  38. :data="props.row.orderList"
  39. :cell-style="{ padding: '0' }"
  40. :row-style="{ height: '35px' }"
  41. v-loading="loading"
  42. header-row-class-name="tableHeader">
  43. <el-table-column label="订单号" prop="orderCode" width="200" />
  44. <el-table-column label="万里牛单号" prop="orderWlnCode" width="140" />
  45. <el-table-column label="SKU品号" prop="skuSpecCode" width="180" />
  46. <el-table-column label="SKU品名" prop="skuSpecName" min-width="180" />
  47. <el-table-column label="出库数量" width="140">
  48. <template #default="{ row }">
  49. <span>{{ row.quantity }}</span>
  50. </template>
  51. </el-table-column>
  52. </el-table>
  53. </div>
  54. </template>
  55. </el-table-column>
  56. <el-table-column label="品号" prop="code" width="180" />
  57. <el-table-column label="品名" prop="name" min-width="220" />
  58. <el-table-column label="仓库" width="160">
  59. <template #default="{ row, $index }">
  60. <el-form-item :prop="'inOutStorageBomList.' + $index + '.warehouseId'" :rules="rules.warehouseId" :inline-message="true" style="width: 100%">
  61. <el-select
  62. v-model="row.warehouseId"
  63. placeholder="请选择仓库"
  64. clearable
  65. style="width: 100%"
  66. @change="
  67. (val) => {
  68. return changeWarehouse(val, row, $index);
  69. }
  70. ">
  71. <el-option v-for="item in warehouseList" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" />
  72. </el-select>
  73. </el-form-item>
  74. </template>
  75. </el-table-column>
  76. <el-table-column label="剩余库存" prop="surplusStock" width="120" />
  77. <el-table-column label="出库数量" width="140">
  78. <template #default="{ row, $index }">
  79. <el-form-item :prop="'inOutStorageBomList.' + $index + '.quantity'" :rules="rules.quantity" :inline-message="true" style="width: 100%">
  80. <el-input-number
  81. onmousewheel="return false;"
  82. v-model="row.quantity"
  83. placeholder="出库数量"
  84. style="width: 100%"
  85. :controls="false"
  86. :min="0"
  87. :precision="0"
  88. disabled />
  89. </el-form-item>
  90. </template>
  91. </el-table-column>
  92. <el-table-column label="操作" align="center" fixed="right" width="80">
  93. <template #default="{ $index }">
  94. <el-button type="danger" @click="clickDelete($index)" text>删除</el-button>
  95. </template>
  96. </el-table-column>
  97. </el-table>
  98. </div>
  99. </template>
  100. </byForm>
  101. <div style="width: 100%; text-align: center; margin: 10px">
  102. <el-button @click="clickCancel()" size="large">取 消</el-button>
  103. <el-button type="primary" @click="submitForm()" size="large" v-preReClick>确 定</el-button>
  104. </div>
  105. </el-card>
  106. </div>
  107. </template>
  108. <script setup>
  109. import byForm from "@/components/byForm/index";
  110. import { ElMessage } from "element-plus";
  111. const { proxy } = getCurrentInstance();
  112. const departmentList = ref([{ dictKey: "0", dictValue: "胜德体育" }]);
  113. const props = defineProps({
  114. selectData: Array,
  115. });
  116. const warehouseList = ref([]);
  117. const submit = ref(null);
  118. const formOption = reactive({
  119. inline: true,
  120. labelWidth: "100px",
  121. itemWidth: 100,
  122. rules: [],
  123. labelPosition: "right",
  124. });
  125. const formData = reactive({
  126. data: {
  127. departmentId: "0",
  128. type: 0,
  129. applicant: proxy.useUserStore().user.nickName,
  130. inOutStorageBomList: [],
  131. },
  132. });
  133. const formConfig = computed(() => {
  134. return [
  135. {
  136. type: "title",
  137. title: "出库信息",
  138. label: "",
  139. },
  140. {
  141. type: "slot",
  142. slotName: "basicInformation",
  143. label: "",
  144. },
  145. {
  146. type: "title",
  147. title: "物料信息",
  148. label: "",
  149. },
  150. {
  151. type: "slot",
  152. slotName: "inOutStorageBomList",
  153. label: "",
  154. },
  155. ];
  156. });
  157. const rules = ref({
  158. departmentId: [{ required: true, message: "请选择事业部", trigger: "change" }],
  159. warehouseId: [{ required: true, message: "请选择仓库", trigger: "change" }],
  160. detailType: [{ required: true, message: "请选择出库类型", trigger: "change" }],
  161. applicant: [{ required: true, message: "请输入申请人", trigger: "blur" }],
  162. quantity: [{ required: true, message: "请输入出库数量", trigger: "blur" }],
  163. });
  164. const getDemandData = () => {
  165. proxy.post("/department/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  166. if (res.rows && res.rows.length > 0) {
  167. departmentList.value = departmentList.value.concat(
  168. res.rows.map((item) => {
  169. return {
  170. dictKey: item.id,
  171. dictValue: item.name,
  172. };
  173. })
  174. );
  175. }
  176. });
  177. };
  178. getDemandData();
  179. const clickDelete = (index) => {
  180. formData.data.inOutStorageBomList.splice(index, 1);
  181. };
  182. const emit = defineEmits(["clickCancel"]);
  183. const duplicateRemoval = (arr) => {
  184. let list = [];
  185. return arr.filter((item) => !list.includes(item) && list.push(item));
  186. };
  187. const submitForm = () => {
  188. submit.value.handleSubmit(async () => {
  189. if (formData.data.inOutStorageBomList && formData.data.inOutStorageBomList.length > 0) {
  190. for (let i = 0; i < formData.data.inOutStorageBomList.length; i++) {
  191. if (Number(formData.data.inOutStorageBomList[i].surplusStock) < Number(formData.data.inOutStorageBomList[i].quantity)) {
  192. return ElMessage("出库数量大于剩余库存数量");
  193. }
  194. }
  195. for (let i = 0; i < warehouseList.value.length; i++) {
  196. let data = proxy.deepClone(formData.data);
  197. data.inOutStorageBomList = data.inOutStorageBomList.filter((item) => item.warehouseId === warehouseList.value[i].dictKey);
  198. if (data.inOutStorageBomList && data.inOutStorageBomList.length > 0) {
  199. data.warehouseId = warehouseList.value[i].dictKey;
  200. const res = await proxy.post("/inOutStorage/add", data);
  201. let orderList = [];
  202. for (let j = 0; j < data.inOutStorageBomList.length; j++) {
  203. orderList = orderList.concat(data.inOutStorageBomList[j].orderList.map((itemOrder) => itemOrder.orderSkuId));
  204. }
  205. const resTwo = await proxy.post("/stockPreparation/submit", duplicateRemoval(orderList));
  206. }
  207. }
  208. ElMessage({ message: "提交完成", type: "success" });
  209. emit("clickCancel", true);
  210. } else {
  211. return ElMessage("请添加BOM");
  212. }
  213. });
  214. };
  215. const clickCancel = () => {
  216. emit("clickCancel", false);
  217. };
  218. const delSomeObjValue = (arr, keyName, valueName) => {
  219. const idArr = []; // 相同的id放在同一数组中
  220. const resultArr = []; // 最终结果数组
  221. for (let i = 0; i < arr.length; i++) {
  222. const index = idArr.indexOf(arr[i][keyName]);
  223. if (index > -1) {
  224. resultArr[index][valueName] += Number(arr[i][valueName]); //取相同id的value累加
  225. } else {
  226. idArr.push(arr[i][keyName]);
  227. resultArr.push(arr[i]);
  228. }
  229. }
  230. return resultArr;
  231. };
  232. const getWarehouse = () => {
  233. return proxy.post("/warehouse/page", { pageNum: 1, pageSize: 999 }).then((res) => {
  234. if (res.rows && res.rows.length > 0) {
  235. warehouseList.value = res.rows
  236. .filter((item) => ["2", "3"].includes(item.type))
  237. .map((item) => {
  238. return {
  239. dictKey: item.id,
  240. dictValue: item.name,
  241. };
  242. });
  243. }
  244. });
  245. };
  246. onMounted(() => {
  247. Promise.all([getWarehouse()]).then(() => {
  248. if (props.selectData && props.selectData.length > 0) {
  249. formData.data.inOutStorageBomList = delSomeObjValue(
  250. props.selectData.map((item) => {
  251. let num = 0;
  252. if (item.quantity) {
  253. num = Number(item.quantity);
  254. }
  255. return {
  256. bomSpecId: item.bomSpecId,
  257. quantity: num,
  258. name: item.bomSpecName,
  259. code: item.bomSpecCode,
  260. warehouseId: "",
  261. surplusStock: 0,
  262. };
  263. }),
  264. "bomSpecId",
  265. "quantity"
  266. ).map((item) => {
  267. return {
  268. ...item,
  269. orderList: props.selectData
  270. .map((item) => {
  271. let num = 0;
  272. if (item.quantity) {
  273. num = Number(item.quantity);
  274. }
  275. return {
  276. bomSpecId: item.bomSpecId,
  277. quantity: num,
  278. orderSkuId: item.orderSkuId,
  279. orderCode: item.orderCode,
  280. orderWlnCode: item.orderWlnCode,
  281. skuSpecCode: item.skuSpecCode,
  282. skuSpecName: item.skuSpecName,
  283. };
  284. })
  285. .filter((itemSelect) => itemSelect.bomSpecId === item.bomSpecId),
  286. };
  287. });
  288. if (formData.data.inOutStorageBomList && formData.data.inOutStorageBomList.length > 0) {
  289. let bomSpecIdList = [];
  290. bomSpecIdList = formData.data.inOutStorageBomList.map((item) => item.bomSpecId);
  291. proxy
  292. .post("/inventory/getQuantity", {
  293. departmentId: formData.data.departmentId,
  294. warehouseId: warehouseList.value[0].dictKey,
  295. bomSpecIdList: bomSpecIdList,
  296. })
  297. .then((resInventory) => {
  298. let bomSpecIdTwoList = [];
  299. for (let i = 0; i < formData.data.inOutStorageBomList.length; i++) {
  300. if (resInventory[formData.data.inOutStorageBomList[i].bomSpecId]) {
  301. formData.data.inOutStorageBomList[i].warehouseId = warehouseList.value[0].dictKey;
  302. formData.data.inOutStorageBomList[i].surplusStock = resInventory[formData.data.inOutStorageBomList[i].bomSpecId];
  303. } else {
  304. bomSpecIdTwoList.push(formData.data.inOutStorageBomList[i].bomSpecId);
  305. }
  306. }
  307. if (bomSpecIdTwoList && bomSpecIdTwoList.length > 0) {
  308. proxy
  309. .post("/inventory/getQuantity", {
  310. departmentId: formData.data.departmentId,
  311. warehouseId: warehouseList.value[1].dictKey,
  312. bomSpecIdList: bomSpecIdTwoList,
  313. })
  314. .then((inventoryTwo) => {
  315. for (let i = 0; i < formData.data.inOutStorageBomList.length; i++) {
  316. if (inventoryTwo[formData.data.inOutStorageBomList[i].bomSpecId]) {
  317. formData.data.inOutStorageBomList[i].warehouseId = warehouseList.value[0].dictKey;
  318. formData.data.inOutStorageBomList[i].surplusStock = inventoryTwo[formData.data.inOutStorageBomList[i].bomSpecId];
  319. }
  320. }
  321. });
  322. }
  323. });
  324. }
  325. }
  326. });
  327. });
  328. const changeWarehouse = (val, item, index) => {
  329. if (val) {
  330. if (formData.data.departmentId) {
  331. proxy
  332. .post("/inventory/getQuantity", {
  333. departmentId: formData.data.departmentId,
  334. warehouseId: val,
  335. bomSpecIdList: [item.bomSpecId],
  336. })
  337. .then((res) => {
  338. if (res[item.bomSpecId]) {
  339. formData.data.inOutStorageBomList[index].surplusStock = res[item.bomSpecId];
  340. } else {
  341. formData.data.inOutStorageBomList[index].surplusStock = 0;
  342. }
  343. });
  344. } else {
  345. return ElMessage("请先选择事业部");
  346. }
  347. } else {
  348. formData.data.inOutStorageBomList[index].surplusStock = 0;
  349. }
  350. };
  351. const changeDepartment = () => {
  352. if (formData.data.inOutStorageBomList && formData.data.inOutStorageBomList.length > 0) {
  353. formData.data.inOutStorageBomList = formData.data.inOutStorageBomList.map((item) => {
  354. return {
  355. ...item,
  356. warehouseId: "",
  357. surplusStock: 0,
  358. };
  359. });
  360. }
  361. };
  362. </script>
  363. <style lang="scss" scoped>
  364. ::v-deep(.el-input-number .el-input__inner) {
  365. text-align: left;
  366. }
  367. :deep(.el-dialog) {
  368. margin-top: 10px !important;
  369. margin-bottom: 10px !important;
  370. }
  371. </style>