add.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. <template>
  2. <view class="mainBox">
  3. <uni-nav-bar
  4. background-color="#157A2C"
  5. color="#fff"
  6. fixed="true"
  7. statusBar="true"
  8. left-icon="back"
  9. :title="this.form.id ? '修改采购需求' : '新建采购需求'"
  10. @clickLeft="back"
  11. >
  12. </uni-nav-bar>
  13. <u-subsection
  14. :list="list"
  15. :current="current"
  16. @change="sectionChange"
  17. ></u-subsection>
  18. <u-cell-group v-show="current == 0">
  19. <u-cell :title="'需求类型'" arrow-direction="down">
  20. <view slot="title" style="display: flex; align-items: center">
  21. <text class="required-mark">*</text>
  22. 需求类型
  23. </view>
  24. <uni-data-picker
  25. v-model="form.sourceType"
  26. slot="value"
  27. placeholder="请选择"
  28. :localdata="requirementSourceType"
  29. @change="sourceCodeOnchange"
  30. >
  31. </uni-data-picker>
  32. </u-cell>
  33. <u-cell :title="'需求单名称'" arrow-direction="down">
  34. <view slot="title" style="display: flex; align-items: center">
  35. <text class="required-mark">*</text>
  36. 需求单名称
  37. </view>
  38. <u--input
  39. slot="value"
  40. placeholder="请输入"
  41. border="surround"
  42. v-model="form.requirementName"
  43. ></u--input>
  44. </u-cell>
  45. <u-cell :title="'需求部门'" arrow-direction="down">
  46. <view slot="title" style="display: flex; align-items: center">
  47. <text class="required-mark">*</text>
  48. 需求部门
  49. </view>
  50. <!-- <u--input slot="value" placeholder="请输入" border="surround" v-model="form.requireDeptId"></u--input> -->
  51. <u--input
  52. slot="value"
  53. @click.native="classification"
  54. style="flex: 1"
  55. border="surround"
  56. placeholder="请选择需求部门"
  57. v-model="form.requireDeptName"
  58. >
  59. </u--input>
  60. </u-cell>
  61. <u-cell :title="'需求人'" arrow-direction="down">
  62. <view slot="title" style="display: flex; align-items: center">
  63. <text class="required-mark">*</text>
  64. 需求人
  65. </view>
  66. <!-- <u--input slot="value" placeholder="请输入" border="requireUserId" v-model="form.name"></u--input> -->
  67. <u--input
  68. slot="value"
  69. style="flex: 1"
  70. border="surround"
  71. v-model="form.requireUserName"
  72. placeholder="请选择需求人"
  73. @click.native="openSelector"
  74. >
  75. </u--input>
  76. </u-cell>
  77. <u-cell
  78. v-if="form.sourceType == 1"
  79. title="销售合同"
  80. arrow-direction="down"
  81. >
  82. <u--input
  83. slot="value"
  84. style="flex: 1"
  85. placeholder="请选择销售合同"
  86. border="surround"
  87. v-model="form.saleContractNo"
  88. @click.native="selectContractShow"
  89. ></u--input>
  90. </u-cell>
  91. <u-cell
  92. v-if="form.sourceType == 1"
  93. title="销售订单"
  94. arrow-direction="down"
  95. >
  96. <!-- <u--input slot="value" placeholder="请输入" border="requireUserId" v-model="form.name"></u--input> -->
  97. <u--input
  98. slot="value"
  99. style="flex: 1"
  100. border="surround"
  101. v-model="form.saleOrderNo"
  102. placeholder="请选择销售订单"
  103. @click.native="slectOrderShow"
  104. >
  105. </u--input>
  106. </u-cell>
  107. <u-cell title="是否接受拆单" arrow-direction="down">
  108. <uni-data-picker
  109. v-model="form.acceptUnpack"
  110. slot="value"
  111. placeholder="请选择"
  112. :localdata="acceptUnpackList"
  113. >
  114. </uni-data-picker>
  115. </u-cell>
  116. <u-cell title="'用途" arrow-direction="down">
  117. <view slot="title" style="display: flex; align-items: center">
  118. <text class="required-mark">*</text>
  119. 用途
  120. </view>
  121. <u--textarea
  122. slot="value"
  123. placeholder="请输入"
  124. border="surround"
  125. v-model="form.useTo"
  126. ></u--textarea>
  127. </u-cell>
  128. <u-cell title="附件" arrow-direction="down">
  129. <view slot="value" style="display: flex; align-items: center">
  130. <fileMain v-model="form.fileId"></fileMain>
  131. </view>
  132. </u-cell>
  133. <u-cell title="备注" arrow-direction="down">
  134. <u--textarea
  135. slot="value"
  136. placeholder="请输入"
  137. border="surround"
  138. v-model="form.remark"
  139. ></u--textarea>
  140. </u-cell>
  141. </u-cell-group>
  142. <view class="footerButton">
  143. <u-button type="default" text="返回" @click="back"></u-button>
  144. <u-button type="primary" @click="save" text="保存"></u-button>
  145. </view>
  146. <produceList
  147. ref="produceListRef"
  148. v-show="current == 1"
  149. :isTemporary="true"
  150. ></produceList>
  151. <ba-tree-picker
  152. ref="treePicker"
  153. key="verify"
  154. :multiple="false"
  155. @select-change="confirm"
  156. title="选择部门"
  157. :selectedData="selectedData"
  158. :localdata="classificationList"
  159. valueKey="id"
  160. textKey="name"
  161. childrenKey="children"
  162. />
  163. <search-select
  164. ref="selector"
  165. v-model="form.requireUserId"
  166. :data-list="executorList"
  167. title="选择需求人"
  168. @change="onClose"
  169. >
  170. </search-select>
  171. <u-toast ref="uToast"></u-toast>
  172. </view>
  173. </template>
  174. <script>
  175. import { getByCode } from "@/api/pda/common.js";
  176. import searchSelect from "@/pages/salesServiceManagement/accessory/components/searchSelect.vue";
  177. import produceList from "../components/produceList.vue";
  178. import fileMain from "@/pages/doc/index.vue";
  179. import { requirementSourceType } from "@/enum/dict";
  180. import { listOrganizations } from "@/api/salesServiceManagement/workOrder/index.js";
  181. import { toTreeData } from "@/utils/utils.js";
  182. import { getUserPage } from "@/api/common.js";
  183. import {
  184. getTableList,
  185. getSaleOrderDetail,
  186. } from "@/api/saleManage/saleorder/index";
  187. import {
  188. getDetail,
  189. addPurchaseNeedManage,
  190. UpdateInformation,
  191. } from "@/api/purchasingManage/purchaseNeedManage.js";
  192. import { getInventoryTotal } from "@/api/pda/workOrder";
  193. import { contactQueryByCategoryIdsAPI } from "@/api/warehouseManagement/index";
  194. export default {
  195. components: {
  196. produceList,
  197. fileMain,
  198. searchSelect,
  199. },
  200. data() {
  201. return {
  202. list: ["基本信息", "需求清单"],
  203. acceptUnpackList: [
  204. { text: "接受", value: 1 },
  205. { text: "不接受", value: 0 },
  206. ],
  207. current: 0,
  208. show: false,
  209. requirementSourceType,
  210. classificationList: [],
  211. isUpdate: false,
  212. purchase_origin: [],
  213. files: [],
  214. form: {
  215. id: "",
  216. receiveDate: null,
  217. remark: null,
  218. requireDeptId: "",
  219. requireDeptName: "",
  220. requireUserId: "",
  221. requireUserName: "",
  222. sourceCode: "",
  223. sourceId: "",
  224. sourceType: "",
  225. sourceTypeName: "",
  226. requirementName: "",
  227. saleContractName: "",
  228. saleContractNo: "",
  229. saleContractId: "",
  230. saleOrderId: "",
  231. saleOrderNo: "",
  232. files: [], //附件集合
  233. acceptUnpack: 1,
  234. detailList: [],
  235. fileId: [],
  236. },
  237. business_opport_code: [],
  238. linkList: [],
  239. selectedData: [], // 使用部门绑定值
  240. executorList: [],
  241. };
  242. },
  243. created() {
  244. this.getByCode();
  245. //选择合同回调
  246. uni.$off("setContractList");
  247. uni.$on("setContractList", async (data) => {
  248. if (data && data.length > 0) {
  249. this.form = Object.assign({}, this.form, {
  250. saleContractId: data[0].id,
  251. saleContractName: data[0].contractName,
  252. saleContractNo: data[0].contractNo,
  253. });
  254. console.log("ddd~~~", data[0]);
  255. this.getSaleOrderList(data[0].id);
  256. }
  257. });
  258. uni.$off("setSaleOrder");
  259. uni.$on("setSaleOrder", async (data) => {
  260. if (data && data.length > 0) {
  261. this.form = Object.assign({}, this.form, {
  262. saleContractId: "",
  263. saleContractName: "",
  264. saleContractNo: "",
  265. saleOrderId: data[0].id,
  266. saleOrderNo: data[0].orderNo,
  267. });
  268. this.getSaleOrderDetail(this.form.saleOrderId);
  269. }
  270. });
  271. },
  272. onLoad(data) {
  273. this.getTreeList();
  274. if (data && data.id) {
  275. this.isUpdate = true;
  276. getDetail(data.id).then(async (res) => {
  277. if (res.fileId) {
  278. res.fileId = JSON.parse(res.fileId);
  279. } else {
  280. res.fileId = [];
  281. }
  282. if (res.requireDeptId) {
  283. this.getUserList(res.requireDeptId);
  284. }
  285. let validItems = res.detailList.filter((item) => item.productCode);
  286. let productIds = validItems.map((item) => item.productId);
  287. let productCodes = validItems.map((item) => item.productCode);
  288. // 批量获取库存和供应商信息
  289. let inventoryTotalList = [];
  290. let supplierObj = {};
  291. if (productIds.length > 0) {
  292. inventoryTotalList = await getInventoryTotal(productCodes);
  293. supplierObj = await contactQueryByCategoryIdsAPI({
  294. categoryIds: productIds,
  295. });
  296. // 更新每个产品的供应商和库存信息
  297. validItems.forEach((item, index) => {
  298. // 找到对应的索引位置
  299. let actualIndex = res.detailList.findIndex(
  300. (i) => i.productCode === item.productCode
  301. );
  302. if (actualIndex !== -1) {
  303. this.$set(
  304. res.detailList[actualIndex],
  305. "supplierList",
  306. supplierObj[item.productId]?.map((i) => ({
  307. ...i,
  308. text: i.name,
  309. value: i.id,
  310. })) || []
  311. );
  312. let find =
  313. inventoryTotalList.find(
  314. (key) => key.code == item.productCode
  315. ) || {};
  316. this.$set(
  317. res.detailList[actualIndex],
  318. "availableCountBase",
  319. find.availableCountBase
  320. );
  321. }
  322. });
  323. }
  324. // 处理数据格式
  325. res.detailList = res.detailList.map((item) => ({
  326. ...item,
  327. // files: item.files || [],
  328. // technicalDrawings: item.technicalDrawings || [],
  329. provenanceName: item.provenance
  330. ? this.getProvenance(item.provenance)
  331. : "",
  332. // modelKey: item.modelKey?.split(',') || [],
  333. // colorKey: item.colorKey?.split(',') || [],
  334. packageDispositionList:
  335. item.packageDispositionList?.map((i) => ({
  336. ...i,
  337. text: i.conversionUnit,
  338. value: i.id,
  339. })) || [],
  340. }));
  341. this.$set(this, "form", res);
  342. this.$nextTick(() => {
  343. this.$refs.produceListRef.init(res.detailList);
  344. });
  345. // }, 300)
  346. });
  347. } else {
  348. const userInfo = uni.getStorageSync("userInfo");
  349. this.$set(this.form, "requireUserId", userInfo.userId);
  350. this.$set(this.form, "requireUserName", userInfo.name);
  351. this.$set(this.form, "requireDeptId", userInfo.groupId);
  352. this.$set(this.form, "requireDeptName", userInfo.groupName);
  353. }
  354. },
  355. onUnload() {
  356. uni.$off("setContractList");
  357. uni.$off("setSaleOrder");
  358. },
  359. methods: {
  360. getProvenance(item) {
  361. // console.log("getProvenance~~~~~", item);
  362. // try {
  363. // 检查item和provenance是否存在
  364. if (!item) {
  365. return "";
  366. }
  367. let arr = item;
  368. if (!Array.isArray(arr)) {
  369. // console.log("arr is not array, convert to array");
  370. arr = arr.split(",");
  371. }
  372. return arr && arr.length
  373. ? arr
  374. .map((i) => {
  375. return this.purchase_origin.find((p) => p.value == i)?.text;
  376. })
  377. .join(",")
  378. : "";
  379. },
  380. async getSaleOrderList(contractId) {
  381. let res = await getTableList({
  382. pageNum: 1,
  383. size: 10,
  384. contractId,
  385. });
  386. this.form.saleOrderId = res.list[0]?.id;
  387. this.form.saleOrderNo = res.list[0]?.orderNo;
  388. this.getSaleOrderDetail(this.form.saleOrderId);
  389. },
  390. async getSaleOrderDetail(id) {
  391. const data = await getSaleOrderDetail(id);
  392. data.productList.forEach((item) => {
  393. item.expectReceiveDate = item.produceDeliveryDeadline;
  394. item.arrivalWay = 1;
  395. item["packageDispositionList"] =
  396. item.packageDispositionList?.map((i) => {
  397. return {
  398. ...i,
  399. text: i.conversionUnit,
  400. value: i.id,
  401. };
  402. }) || [];
  403. });
  404. this.$nextTick(() => {
  405. this.$refs.produceListRef.init(data.productList);
  406. });
  407. },
  408. async getTreeList() {
  409. const data = await listOrganizations({});
  410. let treeList = toTreeData({
  411. data: data || [],
  412. idField: "id",
  413. parentIdField: "parentId",
  414. });
  415. this.classificationList = treeList;
  416. },
  417. // 打开部门弹窗
  418. classification() {
  419. this.$refs.treePicker._show();
  420. },
  421. // 使用部门选择
  422. confirm(id, name) {
  423. this.form.requireDeptName = name;
  424. this.form.requireDeptId = id[0];
  425. this.form.requireUserId = "";
  426. this.form.requireUserName = "";
  427. this.executorList = [];
  428. this.getUserList(id[0]);
  429. this.$refs.selector.clearSearchText();
  430. },
  431. // 打开需求人弹窗
  432. openSelector() {
  433. this.$refs.selector.open();
  434. },
  435. // 获取需求人数据
  436. async getUserList(id) {
  437. let params = {
  438. pageNum: 1,
  439. size: -1,
  440. groupId: id,
  441. };
  442. try {
  443. const res = await getUserPage(params);
  444. let list =
  445. res.list &&
  446. res.list.map((el) => {
  447. return {
  448. text: el.name,
  449. value: el.id,
  450. };
  451. });
  452. this.executorList = list;
  453. } catch (error) {
  454. this.executorList = [];
  455. }
  456. },
  457. // 需求人选择
  458. onClose(item) {
  459. this.form.requireUserName = item.text;
  460. },
  461. //选择合同
  462. selectContractShow() {
  463. console.log("ddd~~~");
  464. uni.navigateTo({
  465. url: "/pages/purchasingManage/components/selectContract?isAll=" + 2,
  466. });
  467. },
  468. slectOrderShow() {
  469. uni.navigateTo({
  470. url: "/pages/purchasingManage/components/selectSaleOrder?isAll=" + 2,
  471. });
  472. },
  473. getByCode() {
  474. const codeS = ["business_opport_code", "purchase_origin"];
  475. codeS.forEach(async (code) => {
  476. const codeValue = await getByCode(code);
  477. this[code] = codeValue.map((item) => {
  478. const key = Object.keys(item)[0];
  479. return {
  480. value: key,
  481. text: item[key],
  482. };
  483. });
  484. });
  485. },
  486. sourceCodeOnchange(e) {
  487. const value = e.detail.value;
  488. this.form.sourceCode = value.map((item) => item.value).toString();
  489. this.form.sourceTypeName = value.map((item) => item.text).toString();
  490. this.form.saleOrderId = "";
  491. this.form.saleOrderNo = "";
  492. this.form.saleContractNo = "";
  493. this.form.saleContractId = "";
  494. this.form.saleContractName = "";
  495. },
  496. radioChange(e) {
  497. this.form.pricingWay = e.detail.value;
  498. this.$nextTick(() => {
  499. this.$refs.produceListRef.getTotalPrice();
  500. });
  501. },
  502. sectionChange(index) {
  503. this.current = index;
  504. },
  505. async save() {
  506. try {
  507. if (!this.form.sourceType) {
  508. this.$refs.uToast.show({
  509. type: "error",
  510. message: "请选择需求类型",
  511. });
  512. return;
  513. }
  514. if (!this.form.requirementName) {
  515. this.$refs.uToast.show({
  516. type: "error",
  517. message: "请输入需求名称",
  518. });
  519. return;
  520. }
  521. if (!this.form.requireDeptName) {
  522. this.$refs.uToast.show({
  523. type: "error",
  524. message: "请选择需求部门",
  525. });
  526. return;
  527. }
  528. if (!this.form.requireUserName) {
  529. this.$refs.uToast.show({
  530. type: "error",
  531. message: "请选择需求人",
  532. });
  533. return;
  534. }
  535. const detailList = this.$refs.produceListRef.getValue();
  536. if (detailList.length == 0) {
  537. this.$refs.uToast.show({
  538. type: "error",
  539. message: "产品清单不能为空",
  540. });
  541. return;
  542. }
  543. let isArrivalBatch = false;
  544. let isError = false;
  545. detailList.forEach((v) => {
  546. if (
  547. v.arrivalWay == 2 &&
  548. (!v.arrivalBatch || v.arrivalBatch.length == 0)
  549. ) {
  550. isArrivalBatch = true;
  551. }
  552. if (
  553. !v.purchaseCount ||
  554. !v.productName ||
  555. !v.arrivalWay ||
  556. (!v.expectReceiveDate && v.arrivalWay == 1)
  557. ) {
  558. isError = true;
  559. }
  560. });
  561. if (isError) {
  562. uni.showToast({ icon: "none", title: "请完善产品信息" });
  563. return;
  564. }
  565. if (isArrivalBatch) {
  566. uni.showToast({ icon: "none", title: "请设置分批时间" });
  567. return;
  568. }
  569. uni.showLoading({
  570. title: "加载中",
  571. });
  572. const data = {
  573. ...this.form,
  574. detailList: detailList,
  575. };
  576. data.fileId = JSON.stringify(data.fileId);
  577. data.detailList.forEach((item) => {
  578. if (item.provenance && typeof item.provenance == "string") {
  579. item.provenance = item.provenance.split(",");
  580. }
  581. });
  582. console.log("data~~~", data);
  583. const requestApi = this.isUpdate
  584. ? UpdateInformation
  585. : addPurchaseNeedManage;
  586. requestApi(data)
  587. .then((res) => {
  588. uni.hideLoading();
  589. this.back();
  590. })
  591. .catch((e) => {
  592. uni.hideLoading();
  593. });
  594. } catch (error) {
  595. uni.hideLoading();
  596. console.log(error, "error");
  597. }
  598. },
  599. },
  600. };
  601. </script>
  602. <style lang="scss" scoped>
  603. .required-mark {
  604. color: #ff3333;
  605. margin-right: 4rpx;
  606. }
  607. /deep/.u-cell__body__content {
  608. flex: none;
  609. margin-right: 16rpx;
  610. }
  611. .mainBox {
  612. padding-bottom: 84rpx;
  613. }
  614. .footerButton {
  615. width: 100%;
  616. height: 84rpx;
  617. display: flex;
  618. position: fixed;
  619. bottom: 0;
  620. z-index: 10;
  621. background-color: #fff;
  622. /deep/.u-button {
  623. height: 100%;
  624. }
  625. > view {
  626. flex: 1;
  627. }
  628. }
  629. // /deep/.u-button {
  630. // // height: 100%;
  631. // }
  632. /deep/.u-subsection__item__text {
  633. font-size: 28rpx !important;
  634. }
  635. /deep/.uni-input-placeholder {
  636. font-size: 28rpx !important;
  637. }
  638. /deep/.selected-item {
  639. font-size: 28rpx !important;
  640. }
  641. /deep/.uni-input-input {
  642. font-size: 28rpx !important;
  643. }
  644. </style>