setPlan.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. <template>
  2. <div class="project-setPlan" v-loading="loading">
  3. <div class="project-setPlan-main">
  4. <div class="project-setPlan-title">商品要求</div>
  5. <div class="project-setPlan-ask-table">
  6. <template v-if="ladder">
  7. <el-table
  8. :data="ladder"
  9. :size="'mini'"
  10. border
  11. stripe
  12. style="width: 100%"
  13. >
  14. <el-table-column label="要求编码" prop="pgNo" width="155px" />
  15. <el-table-column prop="good_type" label="商品类型" width="80px">
  16. <template slot-scope="scope">
  17. <el-tag
  18. :size="'mini'"
  19. v-text="
  20. (
  21. statusOptions.find(
  22. (item) => item.value == scope.row.good_type
  23. ) || {}
  24. ).label || '--'
  25. "
  26. ></el-tag
  27. ></template>
  28. </el-table-column>
  29. <el-table-column prop="budget_price" label="预算单价" width="110" />
  30. <el-table-column prop="num" label="购买数量" width="110" />
  31. <el-table-column prop="cat_name" label="商品分类" />
  32. <el-table-column prop="good_img" label="图片" width="50">
  33. <template slot-scope="scope">
  34. <div
  35. v-if="scope.row.good_img"
  36. style="width: 20px; height: 20px"
  37. class="hover"
  38. v-viewer
  39. >
  40. <img
  41. :src="scope.row.good_img"
  42. style="display: inline-block; width: 100%; height: 100%"
  43. alt=""
  44. />
  45. </div>
  46. </template>
  47. </el-table-column>
  48. <el-table-column prop="good_name" label="商品名称" />
  49. </el-table>
  50. </template>
  51. </div>
  52. <div class="project-setPlan-title">客户意向商品</div>
  53. <div class="project-setPlan-backGood-table">
  54. <el-table
  55. :data="tableData"
  56. :size="'mini'"
  57. border
  58. stripe
  59. ref="multipleTable"
  60. style="width: 100%"
  61. @selection-change="handleSelectionChange"
  62. >
  63. <el-table-column
  64. type="selection"
  65. width="40"
  66. v-if="table_type === 'add'"
  67. >
  68. </el-table-column>
  69. <el-table-column
  70. prop="pgNo"
  71. label="要求编码"
  72. width="155px"
  73. show-overflow-tooltip
  74. />
  75. <el-table-column
  76. prop="origin_price"
  77. label="销售单价"
  78. width="110"
  79. show-overflow-tooltip
  80. />
  81. <el-table-column
  82. prop="num"
  83. label="购买数量"
  84. width="110"
  85. show-overflow-tooltip
  86. />
  87. <el-table-column
  88. prop="good_img"
  89. label="图片"
  90. width="50"
  91. show-overflow-tooltip
  92. >
  93. <template slot-scope="scope">
  94. <div
  95. v-if="scope.row.good_img"
  96. style="width: 20px; height: 20px"
  97. class="hover"
  98. v-viewer
  99. >
  100. <img
  101. :src="scope.row.good_img"
  102. style="display: inline-block; width: 100%; height: 100%"
  103. alt=""
  104. />
  105. </div>
  106. </template>
  107. </el-table-column>
  108. <el-table-column prop="good_name" label="商品名称" min-width="120">
  109. <template slot-scope="scope">
  110. <span>{{ scope.row.good_name }}</span>
  111. <span v-for="(si, sii) in scope.row.specinfo" :key="si.id + sii">
  112. {{ sii === 0 ? "_" : "-" }}{{ si.spec_name }}[{{
  113. si.spec_value_name
  114. }}]
  115. </span>
  116. </template>
  117. </el-table-column>
  118. <el-table-column
  119. prop="class_cat"
  120. label="商品分类"
  121. show-overflow-tooltip
  122. />
  123. <el-table-column
  124. prop="expiry_day"
  125. label="信息有效期"
  126. width="85"
  127. show-overflow-tooltip
  128. />
  129. <el-table-column
  130. prop="work_day"
  131. label="制作工期"
  132. width="70"
  133. show-overflow-tooltip
  134. />
  135. <el-table-column
  136. prop="delivery_day"
  137. label="物流时间"
  138. width="70"
  139. show-overflow-tooltip
  140. />
  141. </el-table>
  142. </div>
  143. <div class="project-setPlan-title">
  144. 项目方案
  145. <span style="margin:0 0 0 50px;font-size:13px;color:#e4393c" v-if="total !== 0 && table_type === 'list'"
  146. >{{ plan_show.status === "1" ? "已选定" : "" }}方案总金额:{{
  147. plan_show.sale_total
  148. }}元</span
  149. >
  150. <el-button-group
  151. :size="'mini'"
  152. class="fr"
  153. v-if="table_type === 'list'"
  154. style="margin: 8px 0 0 0"
  155. >
  156. <el-button
  157. type="primary"
  158. class="fr"
  159. v-if="
  160. powers &&
  161. powers.length > 0 &&
  162. powers.some((item) => item == '064') &&
  163. (status == '3' || status == '4')
  164. "
  165. @click="add_plan"
  166. icon="el-icon-circle-plus-outline"
  167. :size="'mini'"
  168. >添加方案
  169. </el-button>
  170. <el-button
  171. type="primary"
  172. class="fr"
  173. v-if="plan_show.status === '1'"
  174. @click="place_order"
  175. :size="'mini'"
  176. >项目下单<i class="el-icon-shopping-cart-2 el-icon--right"></i>
  177. </el-button>
  178. <el-button
  179. class="fr"
  180. type="primary"
  181. :size="'mini'"
  182. :disabled="index === 0"
  183. v-if="total !== 0"
  184. icon="el-icon-arrow-left"
  185. @click="index--, change_plan()"
  186. ></el-button>
  187. <el-button
  188. type="primary"
  189. class="fr"
  190. v-if="total !== 0"
  191. :size="'mini'"
  192. style="height: 29px"
  193. >方案共{{ index + 1 }}/{{ total }}</el-button
  194. >
  195. <el-button
  196. type="primary"
  197. class="fr"
  198. :disabled="index + 1 === total"
  199. v-if="total !== 0"
  200. @click="index++, change_plan()"
  201. :size="'mini'"
  202. ><i class="el-icon-arrow-right el-icon--right" :size="'mini'"></i
  203. ></el-button>
  204. </el-button-group>
  205. <el-button-group
  206. :size="'mini'"
  207. class="fr"
  208. v-else-if="table_type === 'add'"
  209. style="margin: 8px 0 0 0"
  210. >
  211. <el-button
  212. class="fr"
  213. type="primary"
  214. :size="'mini'"
  215. icon="el-icon-arrow-left"
  216. @click="back_list"
  217. >返回列表</el-button
  218. >
  219. <el-button type="primary" class="fr" @click="save_plan" :size="'mini'"
  220. >保存方案<i class="el-icon-upload el-icon--right"></i>
  221. </el-button>
  222. </el-button-group>
  223. </div>
  224. <div class="project-setPlan-backGood-table">
  225. <el-table
  226. :data="plan_show.feedback"
  227. :size="'mini'"
  228. border
  229. stripe
  230. :ref="'multipleTable' + index"
  231. style="width: 100%"
  232. >
  233. <el-table-column
  234. prop="pgNo"
  235. label="要求编码"
  236. width="155px"
  237. show-overflow-tooltip
  238. />
  239. <el-table-column
  240. prop="origin_price"
  241. label="系统售价单价"
  242. width="110"
  243. show-overflow-tooltip
  244. />
  245. <el-table-column
  246. prop="new_sale_price"
  247. label="当前销售单价"
  248. width="110"
  249. show-overflow-tooltip
  250. >
  251. <template slot-scope="scope">
  252. <digital-input
  253. v-if="table_type === 'add'"
  254. :values="scope.row.new_sale_price"
  255. :placeholder="'售价'"
  256. :min="scope.row.origin_price"
  257. :max="100000000000"
  258. :position="'right'"
  259. :precision="2"
  260. :size="'mini'"
  261. :controls="false"
  262. :append="''"
  263. @reschange="
  264. moq_num_change($event, scope.$index, 'new_sale_price')
  265. "
  266. />
  267. <span v-else>{{ scope.row.sale_price }}元</span>
  268. </template>
  269. </el-table-column>
  270. <el-table-column
  271. prop="origin_num"
  272. label="咨询数量"
  273. width="110"
  274. show-overflow-tooltip
  275. />
  276. <el-table-column
  277. prop="num"
  278. label="购买数量"
  279. width="110"
  280. show-overflow-tooltip
  281. >
  282. <template slot-scope="scope">
  283. <digital-input
  284. v-if="table_type === 'add'"
  285. :values="scope.row.origin_num"
  286. :placeholder="'购买数量'"
  287. :min="scope.row.origin_num"
  288. :max="100000000000"
  289. :position="'right'"
  290. :precision="0"
  291. :size="'mini'"
  292. :controls="false"
  293. :append="''"
  294. @reschange="moq_num_change($event, scope.$index, 'num')"
  295. />
  296. <span v-else>{{ scope.row.num }}</span>
  297. </template>
  298. </el-table-column>
  299. <el-table-column
  300. prop="good_img"
  301. label="图片"
  302. width="50"
  303. show-overflow-tooltip
  304. >
  305. <template slot-scope="scope">
  306. <div
  307. v-if="scope.row.good_img"
  308. style="width: 20px; height: 20px"
  309. class="hover"
  310. v-viewer
  311. >
  312. <img
  313. :src="scope.row.good_img"
  314. style="display: inline-block; width: 100%; height: 100%"
  315. alt=""
  316. />
  317. </div>
  318. </template>
  319. </el-table-column>
  320. <el-table-column prop="good_name" label="商品名称" min-width="120">
  321. <template slot-scope="scope">
  322. <span>{{ scope.row.good_name }}</span>
  323. <span v-for="(si, sii) in scope.row.specinfo" :key="si.id + sii">
  324. {{ sii === 0 ? "_" : "-" }}{{ si.spec_name }}[{{
  325. si.spec_value_name
  326. }}]
  327. </span>
  328. </template>
  329. </el-table-column>
  330. <el-table-column
  331. prop="class_cat"
  332. label="商品分类"
  333. show-overflow-tooltip
  334. />
  335. <el-table-column
  336. prop="expiry_day"
  337. label="信息有效期"
  338. width="85"
  339. show-overflow-tooltip
  340. />
  341. <el-table-column
  342. prop="work_day"
  343. label="制作工期"
  344. width="70"
  345. show-overflow-tooltip
  346. />
  347. <el-table-column
  348. prop="delivery_day"
  349. label="物流时间"
  350. width="70"
  351. show-overflow-tooltip
  352. />
  353. </el-table>
  354. </div>
  355. <buy-good-modal
  356. :showModel="bayGoodShowModel"
  357. :sitem="bayGoodItem"
  358. @cancel="bayGoodShowModel = false"
  359. @refresh="(bayGoodShowModel = false), $emit('resGoodOk')"
  360. />
  361. </div>
  362. </div>
  363. </template>
  364. <script>
  365. import asyncRequest from "@/apis/service/sellOut/project";
  366. import resToken from "@/mixins/resToken";
  367. import columnsForm from "./columnsForm";
  368. import buyGoodModal from "./buyGoodModal";
  369. export default {
  370. name: "setPlan",
  371. props: ["showModel", "sitem", "id", "type", "newTime"],
  372. mixins: [resToken],
  373. components: {
  374. buyGoodModal,
  375. },
  376. computed: {
  377. powers() {
  378. let tran =
  379. this.$store.getters.btnList.find(
  380. (item) => item.menu_route == "projectDetail"
  381. ) || {};
  382. if (tran && tran.action && tran.action.length > 0) {
  383. return tran.action;
  384. } else {
  385. return [];
  386. }
  387. },
  388. },
  389. watch: {
  390. // showModel: function (val) {
  391. // this.showModelThis = val;
  392. // if (val) {
  393. // this.initForm();
  394. // }
  395. // },
  396. newTime: function (val) {
  397. if (val) {
  398. this.initForm();
  399. }
  400. },
  401. },
  402. data() {
  403. return {
  404. showModel: false,
  405. searchItem: {},
  406. loading: false,
  407. allPlanList: [],
  408. bayGoodItem: {},
  409. bayGoodShowModel: false,
  410. ladder: [],
  411. index: 0,
  412. total: 0,
  413. table_type: "list",
  414. // allList: [],
  415. projectNo: "",
  416. status: "",
  417. statusOptions: [
  418. { value: "1", label: "竞品" },
  419. { value: "2", label: "竞聘" },
  420. ],
  421. table: {
  422. stripe: true,
  423. border: true,
  424. // _defaultHeader_: ["setcol"],
  425. },
  426. // 表格 - 列参数
  427. columns: columnsForm,
  428. tableData: [],
  429. multipleSelection: [],
  430. plan_show: {
  431. sale_total: "0",
  432. feedback: [],
  433. },
  434. };
  435. },
  436. mounted() {
  437. this.initForm();
  438. },
  439. methods: {
  440. //初始化整个组件
  441. async initForm() {
  442. this.loading = true;
  443. await this.initListData();
  444. await this.back_list();
  445. this.loading = false;
  446. },
  447. //项目下单
  448. place_order() {
  449. const { company, khName, platform_name, arrtime, project_name } =
  450. this.sitem;
  451. this.bayGoodItem = JSON.parse(
  452. JSON.stringify(this.allPlanList[this.index])
  453. );
  454. this.bayGoodItem.in_company = company;
  455. this.bayGoodItem.in_khname = khName;
  456. this.bayGoodItem.in_platform_name = platform_name;
  457. this.bayGoodItem.in_arrival_time = arrtime;
  458. this.bayGoodItem.in_project_name = project_name;
  459. this.bayGoodShowModel = true;
  460. },
  461. async resetFormData() {
  462. this.pageInfo = {
  463. size: 15,
  464. curr: 1,
  465. total: 0,
  466. };
  467. this.loading = true;
  468. this.tableData = [];
  469. await this.searchList();
  470. },
  471. async back_list() {
  472. this.table_type = "list";
  473. await this.get_plan("1");
  474. },
  475. add_plan() {
  476. const { low_rate } = this.sitem;
  477. let r = low_rate ? low_rate : "0";
  478. if (r * 100 === 0) {
  479. this.$message.warning("暂无项目毛利率,不能制定方案!");
  480. return;
  481. }
  482. this.table_type = "add";
  483. this.plan_show = {
  484. sale_total: "0",
  485. feedback: [],
  486. };
  487. },
  488. moq_num_change(e, index, key) {
  489. this.plan_show.feedback[index][key] = e + "";
  490. this.$set(
  491. this.plan_show.feedback[index],
  492. index,
  493. this.plan_show.feedback[index]
  494. );
  495. },
  496. //初始化整个组件
  497. async initListData() {
  498. console.log(this.sitem);
  499. const { projectNo, ladder, status } = this.sitem;
  500. this.status = status;
  501. this.projectNo = projectNo;
  502. this.ladder = JSON.parse(JSON.stringify(ladder));
  503. this.pageInfo = {
  504. size: 100,
  505. curr: 1,
  506. total: 0,
  507. };
  508. this.tableData = [];
  509. await this.searchList();
  510. },
  511. handleSelectionChange(val) {
  512. this.multipleSelection = val;
  513. let list = JSON.parse(JSON.stringify(this.plan_show.feedback));
  514. this.plan_show = {
  515. sale_total: "0",
  516. feedback: [],
  517. };
  518. this.multipleSelection.forEach((a, i) => {
  519. let fi = list.findIndex((b) => a.id === b.id && b.pgNo === a.pgNo);
  520. if (fi !== -1) {
  521. this.plan_show.feedback.push(JSON.parse(JSON.stringify(list[fi])));
  522. } else {
  523. this.plan_show.feedback.push(
  524. JSON.parse(JSON.stringify(this.multipleSelection[i]))
  525. );
  526. }
  527. });
  528. this.plan_show.feedback.map((e) => {
  529. console.log(e.sale_price);
  530. e.new_sale_price = e.sale_price;
  531. e.origin_num = e.num;
  532. return e;
  533. });
  534. },
  535. async searchList() {
  536. const { size, curr } = this.pageInfo;
  537. // this.loading = true;
  538. let model = {
  539. page: curr,
  540. size: size,
  541. zxNo: "",
  542. infoNo: "",
  543. bidNo: "",
  544. status: "1",
  545. pgNo: "",
  546. projectNo: this.projectNo,
  547. };
  548. const { code, data } = await asyncRequest.back_good_list(model);
  549. if (code === 0) {
  550. const { list, count } = data;
  551. this.tableData = list;
  552. this.tableData.map((v) => {
  553. v.class_cat = "";
  554. if (v.can && v.can.length > 0) {
  555. v.can.forEach((x, i) => {
  556. v.class_cat += i === 0 ? x.name : "/" + x.name;
  557. });
  558. }
  559. return v;
  560. });
  561. this.pageInfo.total = Number(count);
  562. } else if (code >= 100 && code <= 104) {
  563. await this.logout();
  564. } else {
  565. this.tableData = [];
  566. this.pageInfo.total = 0;
  567. }
  568. // this.loading = false;
  569. },
  570. //保存方案
  571. async save_plan() {
  572. if (!this.loading) {
  573. const { feedback } = this.plan_show;
  574. let list = feedback;
  575. let isok = true;
  576. list.forEach((a) => {
  577. let findex = list.findIndex(
  578. (b) => b.pgNo === a.pgNo && a.id !== b.id
  579. );
  580. if (findex !== -1) {
  581. isok = false;
  582. }
  583. });
  584. if (!isok) {
  585. this.$message.warning("一种商品要求只能选择一种商品!");
  586. return;
  587. }
  588. let isall = true;
  589. this.ladder.forEach((a) => {
  590. let to = 0;
  591. list.forEach((b) => {
  592. if (a.pgNo === b.pgNo) {
  593. to++;
  594. }
  595. });
  596. if (to !== 1) {
  597. isall = false;
  598. }
  599. });
  600. if (!isall) {
  601. this.$message.warning("方案必须涵盖全部商品要求!");
  602. return;
  603. }
  604. this.loading = true;
  605. let model = {
  606. feedback: [],
  607. projectNo: this.projectNo,
  608. };
  609. list.forEach((e) => {
  610. let si = {
  611. feedid: e.id,
  612. sale_price: e.new_sale_price,
  613. good_num: e.num,
  614. };
  615. model.feedback.push(si);
  616. });
  617. const { code, data, message } = await asyncRequest.project_make_plan(
  618. model
  619. );
  620. if (code === 0) {
  621. await this.back_list();
  622. } else if (code >= 100 && code <= 104) {
  623. await this.logout();
  624. } else {
  625. this.$message.warning(message);
  626. }
  627. this.loading = false;
  628. }
  629. },
  630. //获取全部方案
  631. async get_plan(type) {
  632. let model = {
  633. projectNo: this.projectNo,
  634. };
  635. const { code, data, message } = await asyncRequest.get_project_plan(
  636. model
  637. );
  638. if (code === 0) {
  639. this.allPlanList = JSON.parse(JSON.stringify(data));
  640. this.total = this.allPlanList.length;
  641. if (type && this.allPlanList.length > 0) {
  642. await this.change_plan("1");
  643. }
  644. } else if (code >= 100 && code <= 104) {
  645. await this.logout();
  646. } else {
  647. this.$message.warning(message);
  648. }
  649. },
  650. //切换当前展示的方案
  651. async change_plan(type) {
  652. this.table_type = "list";
  653. this.plan_show = {
  654. sale_total: "0",
  655. status: "0",
  656. feedback: [],
  657. };
  658. if (type) {
  659. this.index = 0;
  660. }
  661. if (this.status === "4") {
  662. this.allPlanList.forEach((a, ai) => {
  663. if (a.status === "1") {
  664. this.index = ai;
  665. }
  666. });
  667. }
  668. const { sale_total, feedback, status } = JSON.parse(
  669. JSON.stringify(this.allPlanList[this.index])
  670. );
  671. this.plan_show = {
  672. sale_total: sale_total,
  673. status: status,
  674. feedback: JSON.parse(JSON.stringify(feedback)),
  675. };
  676. console.log(this.plan_show);
  677. for (let i = 0; i < this.plan_show.feedback.length; i++) {
  678. this.$set(this.plan_show.feedback[i], i, this.plan_show.feedback[i]);
  679. }
  680. },
  681. },
  682. };
  683. </script>
  684. <style lang="scss" scoped>
  685. .project-setPlan {
  686. box-sizing: border-box;
  687. width: 100%;
  688. .project-setPlan-main {
  689. padding: 2px 16px 16px 16px;
  690. // background: #fefefe;
  691. border-radius: 5px;
  692. overflow: hidden;
  693. border: 1px solid #f0f0f0;
  694. margin: 0 0 16px 0;
  695. .project-setPlan-title {
  696. height: 48px;
  697. line-height: 48px;
  698. color: #676767;
  699. }
  700. }
  701. }
  702. </style>