detailsPage.vue 19 KB

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