detailsPage.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. <template>
  2. <div class="borderless">
  3. <div class="customer-head">
  4. <div class="customer-back">
  5. <!-- <i class="back-icon el-icon-arrow-left"></i><i style="font-style:normal">返回管理列表</i>-->
  6. <el-button
  7. type="danger"
  8. style="border: none;background: none;color: red"
  9. icon="el-icon-arrow-left"
  10. @click="backToList"
  11. >返回列表
  12. </el-button>
  13. </div>
  14. <el-button
  15. class="el-button--small-yh add-customer-btn"
  16. type="primary"
  17. :disabled="disabled"
  18. @click="editCustomer"
  19. >{{ form.id ? "确认修改" : "确认新增" }}
  20. </el-button>
  21. </div>
  22. <div style="margin-top: 60px;margin-bottom:35px">
  23. <containerTitle title="基础信息"></containerTitle>
  24. <basic-container style="margin-bottom: 10px">
  25. <avue-form ref="form" v-model="form" :option="option">
  26. <template slot="portOfLoad">
  27. <port-info
  28. v-model="form.portOfLoad"
  29. :disabled="$route.query.status == 1"
  30. />
  31. </template>
  32. <template slot="portOfDestination">
  33. <port-info
  34. v-model="form.portOfDestination"
  35. :disabled="$route.query.status == 1"
  36. />
  37. </template>
  38. <template slot="corpId">
  39. <select-component
  40. v-model="form.corpId"
  41. :configuration="configuration"
  42. ></select-component>
  43. </template>
  44. <template slot="exchangeRate">
  45. <el-input
  46. size="mini"
  47. v-model="form.exchangeRate"
  48. oninput='this.value=this.value.replace(/[^(\d.)]/g,"").replace(/^(\d+)\.(\d\d).*$/, "$1.$2")'
  49. @change="rateChange"
  50. placeholder="请输入 汇率"
  51. ><template slot="append">%</template></el-input
  52. >
  53. </template>
  54. </avue-form>
  55. </basic-container>
  56. <containerTitle title="商品信息"></containerTitle>
  57. <basic-container>
  58. <avue-crud
  59. :ref="crud"
  60. :data="data"
  61. :option="tableOption"
  62. @row-del="rowDel"
  63. >
  64. <template slot="price" slot-scope="{ row }">
  65. <el-input
  66. v-if="row.$cellEdit"
  67. v-model="row.price"
  68. size="small"
  69. oninput='this.value=this.value.replace(/[^(\d.)]/g,"").replace(/^(\d+)\.(\d\d).*$/, "$1.$2")'
  70. @change="priceChange(row)"
  71. ></el-input>
  72. <span v-else>{{ row.price }}</span>
  73. </template>
  74. <template slot="orderQuantity" slot-scope="{ row }">
  75. <el-input
  76. v-if="row.$cellEdit"
  77. v-model="row.orderQuantity"
  78. size="small"
  79. oninput='this.value=this.value.replace(/[^(\d.)]/g,"").replace(/^(\d+)\.(\d\d).*$/, "$1.$2")'
  80. @change="quantityChange(row)"
  81. ></el-input>
  82. <span v-else>{{ row.orderQuantity }}</span>
  83. </template>
  84. <template slot="itemType" slot-scope="{ row }">
  85. <el-select
  86. v-if="row.$cellEdit"
  87. v-model="row.itemType"
  88. filterable
  89. allow-create
  90. default-first-option
  91. placeholder="请输入"
  92. @focus="itemTypeFocus(row)"
  93. >
  94. <el-option
  95. v-for="(item, index) in itemtypeList"
  96. :key="index"
  97. :label="item.value"
  98. :value="item.value"
  99. >
  100. </el-option>
  101. </el-select>
  102. <span v-else>{{ row.itemType }}</span>
  103. </template>
  104. <template slot="menuLeft">
  105. <el-button
  106. type="primary"
  107. icon="el-icon-plus"
  108. size="small"
  109. @click.stop="newDetails"
  110. >新增明细</el-button
  111. >
  112. <el-button
  113. type="info"
  114. icon="el-icon-printer"
  115. size="small"
  116. @click.stop="openReport()"
  117. >报 表</el-button
  118. >
  119. </template>
  120. <template slot="menu" slot-scope="scope">
  121. <el-button
  122. v-if="scope.row.$cellEdit"
  123. size="small"
  124. icon="el-icon-edit"
  125. type="text"
  126. @click="rowDel(scope.row, scope.index)"
  127. >删 除</el-button
  128. >
  129. </template>
  130. </avue-crud>
  131. </basic-container>
  132. </div>
  133. <el-dialog
  134. title="导入商品"
  135. append-to-body
  136. class="el-dialogDeep"
  137. :visible.sync="dialogVisible"
  138. width="60%"
  139. :close-on-click-modal="false"
  140. :destroy-on-close="true"
  141. :close-on-press-escape="false"
  142. @close="closeGoods"
  143. top="10vh"
  144. >
  145. <span>
  146. <el-row>
  147. <el-col :span="5">
  148. <div>
  149. <el-scrollbar>
  150. <basic-container style="margin-top:45px">
  151. <avue-tree :option="treeOption" @node-click="nodeClick" />
  152. </basic-container>
  153. </el-scrollbar>
  154. </div>
  155. </el-col>
  156. <el-col :span="19">
  157. <avue-crud
  158. :option="goodsOption"
  159. :table-loading="loading"
  160. :data="goodsList"
  161. ref="goodsCrud"
  162. @refresh-change="refreshChange"
  163. @selection-change="selectionChange"
  164. @row-click="rowClick"
  165. :page.sync="page"
  166. @on-load="onLoad"
  167. ></avue-crud>
  168. </el-col>
  169. </el-row>
  170. </span>
  171. <span slot="footer" class="dialog-footer">
  172. <el-button @click="dialogVisible = false">取 消</el-button>
  173. <el-button
  174. type="primary"
  175. @click="importGoods"
  176. :disabled="selectionList.length == 0"
  177. >导入</el-button
  178. >
  179. </span>
  180. </el-dialog>
  181. <report-dialog
  182. :switchDialog="switchDialog"
  183. :reportId="form.id"
  184. reportName="客户询价"
  185. @onClose="onClose()"
  186. ></report-dialog>
  187. </div>
  188. </template>
  189. <script>
  190. import tableOption from "./config/customerContact.json";
  191. import goodsOption from "./config/commodity.json";
  192. import {
  193. detail,
  194. submit,
  195. delItem,
  196. getDeptLazyTree,
  197. getGoods,
  198. getPorts,
  199. getSpecification
  200. } from "@/api/basicData/purchaseInquiry";
  201. import reportDialog from "@/components/report-dialog/main";
  202. import { isvalidatemobile, validatename } from "@/util/validate";
  203. import _ from "lodash";
  204. export default {
  205. name: "detailsPageEdit",
  206. data() {
  207. const validatePhone = (rule, value, callback) => {
  208. if (value != "") {
  209. if (isvalidatemobile(value)[0]) {
  210. this.$message.error("手机号码格式不正确");
  211. callback(new Error(isvalidatemobile(value)[1]));
  212. } else {
  213. callback();
  214. }
  215. } else {
  216. callback();
  217. }
  218. };
  219. const validateName = (rule, value, callback) => {
  220. if (value != "") {
  221. if (validatename(value)) {
  222. this.$message.error("联系人格式不正确");
  223. callback(new Error(validatename(value)));
  224. } else {
  225. callback();
  226. }
  227. } else {
  228. callback();
  229. }
  230. };
  231. return {
  232. configuration: {
  233. multipleChoices: false,
  234. multiple: false,
  235. collapseTags: false,
  236. placeholder: "请点击右边按钮选择",
  237. dicData: []
  238. },
  239. switchDialog: false,
  240. form: {},
  241. disabled: false,
  242. dialogVisible: false,
  243. tableOption: tableOption,
  244. option: {
  245. menuBtn: false,
  246. labelWidth: 100,
  247. column: [
  248. {
  249. label: "客户名称",
  250. prop: "corpId",
  251. rules: [
  252. {
  253. required: true,
  254. message: "",
  255. trigger: "blur"
  256. }
  257. ],
  258. span: 8,
  259. slot: true
  260. },
  261. {
  262. label: "系统号",
  263. prop: "sysNo",
  264. span: 8
  265. },
  266. {
  267. label: "订单状态",
  268. prop: "orderStatus",
  269. span: 8,
  270. type: "select",
  271. dicUrl: "/api/blade-system/dict-biz/dictionary?code=order_status",
  272. props: {
  273. label: "dictValue",
  274. value: "dictValue"
  275. }
  276. },
  277. {
  278. label: "联系人",
  279. prop: "corpAttn",
  280. span: 8,
  281. rules: [{ validator: validateName, trigger: "blur" }]
  282. },
  283. {
  284. label: "电话",
  285. prop: "corpTel",
  286. span: 8,
  287. rules: [{ validator: validatePhone, trigger: "blur" }]
  288. },
  289. {
  290. label: "起运港",
  291. prop: "portOfLoad",
  292. span: 8,
  293. type: "select",
  294. filterable: true,
  295. dicData: [],
  296. props: {
  297. label: "name",
  298. value: "name"
  299. }
  300. },
  301. {
  302. label: "目的港",
  303. prop: "portOfDestination",
  304. span: 8,
  305. type: "select",
  306. filterable: true,
  307. dicData: [],
  308. props: {
  309. label: "name",
  310. value: "name"
  311. }
  312. },
  313. {
  314. label: "运输方式",
  315. prop: "transport",
  316. span: 8,
  317. type: "select",
  318. dicUrl: "/api/blade-system/dict-biz/dictionary?code=mode_transport",
  319. props: {
  320. label: "dictValue",
  321. value: "dictValue"
  322. }
  323. },
  324. {
  325. label: "价格条款",
  326. prop: "priceTerms",
  327. span: 8,
  328. type: "select",
  329. dicUrl: "/api/blade-system/dict-biz/dictionary?code=pricing_terms",
  330. props: {
  331. label: "dictValue",
  332. value: "dictValue"
  333. }
  334. },
  335. {
  336. label: "条款说明",
  337. prop: "priceTermsDescription",
  338. span: 8
  339. },
  340. {
  341. label: "订单日期",
  342. prop: "businesDate",
  343. span: 8,
  344. type: "date",
  345. format: "yyyy-MM-dd",
  346. valueFormat: "yyyy-MM-dd 00:00:00"
  347. },
  348. {
  349. label: "有效日期",
  350. prop: "dateValidity",
  351. span: 8,
  352. type: "date",
  353. format: "yyyy-MM-dd",
  354. valueFormat: "yyyy-MM-dd 00:00:00"
  355. },
  356. {
  357. label: "收款方式",
  358. prop: "paymentType",
  359. span: 8,
  360. type: "select",
  361. dicUrl: "/api/blade-system/dict-biz/dictionary?code=payment_term",
  362. props: {
  363. label: "dictValue",
  364. value: "dictValue"
  365. }
  366. },
  367. {
  368. label: "收款说明",
  369. prop: "paymentTypeDescription",
  370. span: 8
  371. },
  372. {
  373. label: "币别",
  374. prop: "currency",
  375. span: 8,
  376. type: "select",
  377. dicUrl: "/api/blade-system/dict-biz/dictionary?code=currency",
  378. props: {
  379. label: "dictValue",
  380. value: "dictValue"
  381. }
  382. },
  383. {
  384. label: "汇率",
  385. prop: "exchangeRate",
  386. span: 8,
  387. slot: true
  388. },
  389. {
  390. label: "备注",
  391. prop: "orderRemark",
  392. type: "textarea",
  393. minRows: 2,
  394. span: 16
  395. }
  396. ]
  397. },
  398. treeOption: {
  399. nodeKey: "id",
  400. lazy: true,
  401. treeLoad: function(node, resolve) {
  402. const parentId = node.level === 0 ? 0 : node.data.id;
  403. getDeptLazyTree(parentId).then(res => {
  404. resolve(
  405. res.data.data.map(item => {
  406. return {
  407. ...item,
  408. leaf: !item.hasChildren
  409. };
  410. })
  411. );
  412. });
  413. },
  414. addBtn: false,
  415. menu: false,
  416. size: "small",
  417. props: {
  418. label: "title",
  419. value: "value",
  420. children: "children"
  421. }
  422. },
  423. page: {
  424. pageSize: 10,
  425. currentPage: 1,
  426. total: 0
  427. },
  428. loading: false,
  429. goodsOption: goodsOption,
  430. data: [],
  431. goodsList: [],
  432. selectionList: [],
  433. treeDeptId: null,
  434. itemtypeList:[]
  435. };
  436. },
  437. props: {
  438. detailData: {
  439. type: Object
  440. }
  441. },
  442. components: {
  443. reportDialog
  444. },
  445. created() {
  446. if (this.detailData.id) {
  447. this.getDetail(this.detailData.id);
  448. }
  449. if (this.detailData.status == 1) {
  450. this.option.disabled = true;
  451. }
  452. let _this = this;
  453. this.tableOption.column.forEach(e => {
  454. if (e.prop == "taxRate") {
  455. e.formatter = function(row) {
  456. return _this.textFormat(
  457. Number(row.taxRate ? row.taxRate : 0) / 100,
  458. "0.00%"
  459. );
  460. };
  461. }
  462. if (e.prop == "amount" || e.prop == "price") {
  463. e.formatter = function(row) {
  464. return _this.textFormat(
  465. Number(row.amount ? row.amount : 0),
  466. "#,##0.00"
  467. );
  468. };
  469. }
  470. });
  471. getPorts().then(res => {
  472. this.findObject(this.option.column, "portOfLoad").dicData = res.data;
  473. this.findObject(this.option.column, "portOfDestination").dicData =
  474. res.data;
  475. });
  476. },
  477. methods: {
  478. itemTypeFocus(row) {
  479. this.itemtypeList = [];
  480. getSpecification({ goodId: row.itemId }).then(res => {
  481. const data = res.data.data;
  482. this.itemtypeList = data.map(item => ({ value: item }));
  483. });
  484. },
  485. priceChange(row) {
  486. console.log(row);
  487. if (!row.price) {
  488. row.price = 0;
  489. } else {
  490. row.amount = _.multiply(row.price, row.orderQuantity).toFixed(2);
  491. }
  492. },
  493. quantityChange(row) {
  494. if (!row.orderQuantity) {
  495. row.orderQuantity = 0;
  496. } else {
  497. row.amount = _.multiply(row.price, row.orderQuantity).toFixed(2);
  498. }
  499. },
  500. rateChange(row) {
  501. console.log(row);
  502. if (row >= 100) {
  503. this.form.exchangeRate = 0;
  504. this.$message.error("汇率不能超过100%");
  505. }
  506. },
  507. rowSave(row) {
  508. console.log(row);
  509. this.$set(row, "$cellEdit", false);
  510. },
  511. rowDel(row, index) {
  512. if (row.id) {
  513. delItem(row.id).then(res => {
  514. this.$message({
  515. type: "success",
  516. message: "操作成功!"
  517. });
  518. this.data.splice(index, 1);
  519. });
  520. } else {
  521. this.$message({
  522. type: "success",
  523. message: "操作成功!"
  524. });
  525. this.data.splice(index, 1);
  526. }
  527. },
  528. importGoods() {
  529. this.selectionList.forEach(e => {
  530. this.data.push({
  531. itemId: e.id,
  532. code: e.code,
  533. cname: e.cname,
  534. priceCategory: e.goodsTypeName,
  535. itemUrl: e.url,
  536. itemProp: null,
  537. itemDescription: null,
  538. itemType: null,
  539. orderQuantity: 0,
  540. tradeTerms: null,
  541. price: 0,
  542. amount: 0,
  543. taxRate: 0,
  544. unit: e.unit,
  545. remarks: null,
  546. $cellEdit: true
  547. });
  548. });
  549. this.dialogVisible = false;
  550. },
  551. closeGoods() {
  552. this.selectionList = [];
  553. this.treeDeptId = "";
  554. },
  555. selectionChange(list) {
  556. this.selectionList = list;
  557. },
  558. rowClick(row) {
  559. this.$refs.goodsCrud.toggleSelection([this.goodsList[row.$index]]);
  560. },
  561. nodeClick(data) {
  562. this.treeDeptId = data.id;
  563. this.page.currentPage = 1;
  564. this.onLoad(this.page);
  565. },
  566. //费用查询
  567. onLoad(page, params = {}) {
  568. this.loading = true;
  569. getGoods(page.currentPage, page.pageSize, this.treeDeptId).then(res => {
  570. const data = res.data.data;
  571. this.page.total = data.total;
  572. this.goodsList = data.records;
  573. this.loading = false;
  574. if (this.page.total) {
  575. this.goodsOption.height = window.innerHeight - 550;
  576. } else {
  577. this.goodsOption.height = window.innerHeight - 475;
  578. }
  579. });
  580. },
  581. //商品明细导入
  582. newDetails() {
  583. this.dialogVisible = !this.dialogVisible;
  584. },
  585. getDetail(id) {
  586. console.log(id);
  587. detail(id).then(res => {
  588. this.form = res.data.data;
  589. this.data = res.data.data.itemsVOList ? res.data.data.itemsVOList : [];
  590. this.configuration.dicData = this.form.corpsName;
  591. });
  592. },
  593. //修改提交触发
  594. editCustomer() {
  595. this.$refs["form"].validate((valid, done) => {
  596. done();
  597. if (valid) {
  598. submit({
  599. ...this.form,
  600. orderItemsList: this.data
  601. }).then(res => {
  602. this.$message.success(this.form.id ? "修改成功" : "提交成功");
  603. });
  604. } else {
  605. return false;
  606. }
  607. });
  608. },
  609. //返回列表
  610. backToList() {
  611. this.$emit("goBack");
  612. },
  613. openReport() {
  614. this.switchDialog = !this.switchDialog;
  615. },
  616. onClose(val) {
  617. this.switchDialog = val;
  618. }
  619. }
  620. };
  621. </script>
  622. <style lang="scss" scoped>
  623. .customer-head {
  624. position: fixed;
  625. top: 105px;
  626. width: 100%;
  627. margin-left: -10px;
  628. height: 62px;
  629. background: #ffffff;
  630. box-shadow: 0 4px 12px 0px rgba(232, 232, 235, 1);
  631. z-index: 999;
  632. }
  633. .customer-back {
  634. cursor: pointer;
  635. line-height: 62px;
  636. font-size: 16px;
  637. color: #323233;
  638. font-weight: 400;
  639. }
  640. .back-icon {
  641. line-height: 64px;
  642. font-size: 20px;
  643. margin-right: 8px;
  644. }
  645. .copy-customer-btn {
  646. position: fixed;
  647. right: 140px;
  648. top: 115px;
  649. }
  650. .add-customer-btn {
  651. position: fixed;
  652. right: 36px;
  653. top: 115px;
  654. }
  655. ::v-deep .el-form-item {
  656. margin-bottom: 8px;
  657. }
  658. ::v-deep .el-form-item__error {
  659. display: none;
  660. }
  661. ::v-deep .select-component {
  662. display: flex;
  663. }
  664. </style>