index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. <template>
  2. <div>
  3. <basic-container v-show="show && showInfo" class="page-crad">
  4. <table border="0" width="100%" style="margin-bottom:20px;" v-loading="loading" :option="option">
  5. <tr>
  6. <td class="stat-td">
  7. <img src="@/assets/img/contractAmountBg.png" class="stat-img">
  8. <div class="stat-tip">
  9. <div class="money">
  10. <span style="font-size:20px;">¥</span>
  11. <avue-count-up :end="form.totalAmount"></avue-count-up>
  12. </div>
  13. <div class="title">合同金额</div>
  14. </div>
  15. </td>
  16. <!-- <td class="stat-td">
  17. <img src="@/assets/img/deliveredBg.png" class="stat-img">
  18. <div class="stat-tip">
  19. <div class="money">
  20. <span style="font-size:20px;">¥</span>
  21. <avue-count-up :end="form.deliveringAmount"></avue-count-up>
  22. </div>
  23. <div class="title">已送货</div>
  24. </div>
  25. </td>
  26. <td class="stat-td">
  27. <img src="@/assets/img/advanceCollectionBg.png" class="stat-img">
  28. <div class="stat-tip">
  29. <div class="money">
  30. <span style="font-size:20px;">¥</span>
  31. <avue-count-up :end="form.advancePayment"></avue-count-up>
  32. </div>
  33. <div class="title">预收款</div>
  34. <div class="title">(积累预收:)</div>
  35. </div>
  36. </td> -->
  37. <td class="stat-td">
  38. <img src="@/assets/img/uncollectedBg.png" class="stat-img">
  39. <div class="stat-tip">
  40. <div class="money">
  41. <span style="font-size:20px;">¥</span>
  42. <avue-count-up :end="form.paidAmount"></avue-count-up>
  43. </div>
  44. <div class="title">未收款</div>
  45. <!-- <div class="title">(积累欠款:)</div> -->
  46. </div>
  47. </td>
  48. <td class="stat-td">
  49. <img src="@/assets/img/receivableBg.png" class="stat-img">
  50. <div class="stat-tip">
  51. <div class="money">
  52. <span style="font-size:20px;">¥</span>
  53. <avue-count-up :end="form.unpaidAmount"></avue-count-up>
  54. </div>
  55. <div class="title">已收款</div>
  56. </div>
  57. </td>
  58. </tr>
  59. </table>
  60. <el-row>
  61. <el-col :span="4">
  62. <avue-tree :option="treeOption" :data="treeData" @node-click="nodeClick" style="height:73vh;"
  63. @save="corpTypeVisible = true">
  64. <template slot="addBtn">
  65. <i class="el-icon-setting" style="font-size:18px;line-height: 30px;width: 20px;padding: 0 10px;"
  66. @click="corpTypeVisible = true"></i>
  67. </template>
  68. </avue-tree>
  69. </el-col>
  70. <el-col :span="20">
  71. <avue-crud ref="crud" :option="option" :data="dataList" :page.sync="page" :search.sync="search"
  72. @search-change="searchChange" @current-change="currentChange" @size-change="sizeChange"
  73. @refresh-change="refreshChange" @on-load="onLoad" :table-loading="loading" @saveColumn="saveColumn"
  74. @resetColumn="resetColumn" :cell-style="cellStyle" @search-criteria-switch="searchCriteriaSwitch">
  75. <template slot="menuLeft">
  76. <!-- <el-button type="primary" size="mini" @click.stop="newAdd()">新建客户
  77. </el-button>
  78. <el-button type="primary" size="mini" icon="el-icon-bottom" @click="excelBox = true">导入
  79. </el-button> -->
  80. <!-- <el-button type="primary" size="mini" icon="el-icon-bottom" @click="outExport">导出
  81. </el-button> -->
  82. </template>
  83. <template slot-scope="{ row, index }" slot="cname">
  84. <span style="color: #409EFF;cursor: pointer" @click.stop="viewInfo(row)">{{ row.cname }}
  85. </span>
  86. </template>
  87. <template slot="idsSearch">
  88. <crop-select v-model="search.ids" corpType="KH"></crop-select>
  89. </template>
  90. <template slot="dateSearch">
  91. <el-date-picker v-model="search.date" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期"
  92. format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" :default-time="['00:00:00', '23:59:59']"
  93. :picker-options="pickerOptions">
  94. </el-date-picker>
  95. </template>
  96. <template slot-scope="{ row, index }" slot="menu">
  97. <el-tooltip class="item" effect="dark" content="编辑" placement="top">
  98. <i class="tradingIcon icon-edit" @click.stop="editOpen(row, 2)" />
  99. </el-tooltip>
  100. <el-tooltip class="item" effect="dark" content="收款" placement="top">
  101. <i class="tradingIcon icon-proceeds" />
  102. </el-tooltip>
  103. <el-tooltip class="item" effect="dark" content="发货" placement="top">
  104. <i class="tradingIcon icon-deliver" />
  105. </el-tooltip>
  106. <el-tooltip class="item" effect="dark" content="对账" placement="top">
  107. <i class="tradingIcon icon-reconciliation" />
  108. </el-tooltip>
  109. <el-tooltip class="item" effect="dark" content="删除" placement="top">
  110. <i class="tradingIcon icon-del" style="color: #FF0000" @click.stop="rowDel(row)" />
  111. </el-tooltip>
  112. <!-- <el-button type="text" size="small" @click.stop="editOpen(row, 2)">
  113. 查看
  114. </el-button>
  115. <el-button type="text" size="small" @click.stop="rowDel(row, index)">
  116. 删除
  117. </el-button> -->
  118. </template>
  119. </avue-crud>
  120. </el-col>
  121. </el-row>
  122. </basic-container>
  123. <details-page v-if="!show" @goBack="goBack()" :detailData="detailData" />
  124. <details-info v-if="!showInfo" @goBack="goBack()" @editOpen="editOpen" :detailData="detailData" />
  125. <el-dialog title="设置客户分类" v-dialogDrag :visible.sync="corpTypeVisible" class="avue-dialog" width="80%" append-to-body
  126. @closed="corpTypeClosed">
  127. <span>
  128. <corp-type></corp-type>
  129. <!-- <avue-form :key="reload" ref="corpType" v-model="form4" :option="option4" style="margin-top:20px">
  130. </avue-form> -->
  131. </span>
  132. <div class="avue-dialog__footer">
  133. <el-button @click="corpTypeVisible = false" size="mini">取 消</el-button>
  134. <el-button @click="addCorpType" type="primary" size="mini">确 定</el-button>
  135. </div>
  136. </el-dialog>
  137. <el-dialog title="导入客户" append-to-body :visible.sync="excelBox" width="555px" :close-on-click-modal="false"
  138. v-dialog-drag>
  139. <avue-form :option="excelOption" v-model="excelForm" table-loading="excelLoading" :upload-before="uploadBefore"
  140. :upload-after="uploadAfter">
  141. <template slot="excelTemplate">
  142. <el-button type="primary" @click="derivation">
  143. 点击下载<i class="el-icon-download el-icon--right"></i>
  144. </el-button>
  145. </template>
  146. </avue-form>
  147. <p style="text-align: center;color: #DC0505">
  148. 温馨提示 第一次导入时请先下载模板
  149. </p>
  150. </el-dialog>
  151. </div>
  152. </template>
  153. <script>
  154. import detailsInfo from "./detailsInfo";
  155. import detailsPage from "./detailsPage";
  156. import { option } from "./js/optionList";
  157. import {
  158. getCorpType,
  159. } from "@/api/tirePartsMall/basicData/customerInformation";
  160. import { getList, pageStatistics, remove, addCorpType, customerList } from "@/api/basicData/customerTransactions";
  161. import corpType from '@/components/corpType/index'
  162. import { getToken } from "@/util/auth";
  163. export default {
  164. name: "index",
  165. data() {
  166. return {
  167. corpTypeVisible: false,
  168. excelForm: {},
  169. excelOption: {
  170. submitBtn: false,
  171. emptyBtn: false,
  172. column: [
  173. {
  174. label: "模板下载",
  175. prop: "excelTemplate",
  176. formslot: true,
  177. span: 24
  178. },
  179. {
  180. label: "导入客户",
  181. prop: "excelFile",
  182. type: "upload",
  183. drag: true,
  184. loadText: "客户上传中,请稍等",
  185. accept: '.xls,.xlsx',
  186. span: 24,
  187. propsHttp: {
  188. res: "data"
  189. },
  190. tip: "请上传 .xls,.xlsx 标准格式文件",
  191. action: "/api/blade-client/partsCorps/import-desc"
  192. }
  193. ]
  194. },
  195. src: '',
  196. show: true,
  197. excelBox: false,
  198. showInfo: true,
  199. loading: false,
  200. search: {},
  201. detailData: {},
  202. dataList: [],
  203. selectionList: [],
  204. page: {
  205. pageSize: 20,
  206. currentPage: 1,
  207. total: 0,
  208. pageSizes: [10, 20, 30, 40, 50, 100, 200, 300, 400, 500]
  209. },
  210. form: {
  211. totalAmount: 0,
  212. paidAmount: 0,
  213. unpaidAmount: 0
  214. },
  215. formSerach: {},
  216. pickerOptions: {
  217. shortcuts: [
  218. {
  219. text: '当天',
  220. onClick(picker) {
  221. const date = new Date();
  222. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
  223. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  224. picker.$emit('pick', [start, end]);
  225. }
  226. },
  227. {
  228. text: '昨天',
  229. onClick(picker) {
  230. const date = new Date();
  231. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 0, 0, 0);
  232. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 1, 23, 59, 59);
  233. picker.$emit('pick', [start, end]);
  234. }
  235. }, {
  236. text: '当月',
  237. onClick(picker) {
  238. const date = new Date();
  239. const start = new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0);
  240. const end = new Date(date.getFullYear(), date.getMonth() + 1, 0, 23, 59, 59);
  241. picker.$emit('pick', [start, end]);
  242. }
  243. }, {
  244. text: '当季',
  245. onClick(picker) {
  246. const date = new Date();
  247. const start = new Date(date.getFullYear(), parseInt(date.getMonth() / 3) * 3, 1, 0, 0, 0);
  248. const end = new Date(date.getFullYear(), parseInt(date.getMonth() / 3) * 3 + 3, 0, 23, 59, 59);
  249. picker.$emit('pick', [start, end]);
  250. }
  251. }, {
  252. text: '当年',
  253. onClick(picker) {
  254. const date = new Date();
  255. const start = new Date(date.getFullYear(), date.getMonth(), 1, 0, 0, 0);
  256. const end = new Date(date.getFullYear() + 1, 0, 0, 23, 59, 59);
  257. picker.$emit('pick', [start, end]);
  258. }
  259. }, {
  260. text: '最近一周',
  261. onClick(picker) {
  262. const date = new Date();
  263. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7, 0, 0, 0);
  264. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  265. picker.$emit('pick', [start, end]);
  266. }
  267. }, {
  268. text: '最近二周',
  269. onClick(picker) {
  270. const date = new Date();
  271. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7 * 2, 0, 0, 0);
  272. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  273. picker.$emit('pick', [start, end]);
  274. }
  275. }, {
  276. text: '最近三周',
  277. onClick(picker) {
  278. const date = new Date();
  279. const start = new Date(date.getFullYear(), date.getMonth(), date.getDate() - 7 * 3, 0, 0, 0);
  280. const end = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59);
  281. picker.$emit('pick', [start, end]);
  282. }
  283. }]
  284. },
  285. treeOption: {
  286. addBtn: false,
  287. menu: false,
  288. size: "small",
  289. props: {
  290. labelText: "标题",
  291. label: "title",
  292. value: "value",
  293. }
  294. },
  295. treeData: [],
  296. form4: {},
  297. option4: {
  298. menuBtn: false,
  299. labelWidth: 80,
  300. column: [
  301. {
  302. label: "分类名称",
  303. prop: "cname",
  304. rules: [
  305. {
  306. required: true,
  307. message: "",
  308. trigger: "blur"
  309. }
  310. ],
  311. span: 24,
  312. },
  313. {
  314. label: "上级类型",
  315. prop: "parentId",
  316. dicData: [],
  317. type: "tree",
  318. props: {
  319. label: "cname",
  320. value: "id"
  321. },
  322. span: 24,
  323. }
  324. ]
  325. },
  326. hostUrl: '',
  327. option: {}
  328. };
  329. },
  330. components: {
  331. detailsPage,
  332. detailsInfo,
  333. corpType
  334. },
  335. async created() {
  336. this.option = await this.getColumnData(this.getColumnName(277.2), option);
  337. this.option.height = window.innerHeight - 330;
  338. this.getAllWorkDicts()
  339. },
  340. activated() {
  341. this.$refs.crud.refreshTable();
  342. },
  343. methods: {
  344. derivation() {
  345. window.open(
  346. `/api/blade-client/partsCorps/export-template?${this.website.tokenHeader
  347. }=${getToken()}`
  348. );
  349. },
  350. //导出
  351. outExport() {
  352. let config = { params: { ...this.search } }
  353. if (config.params) {
  354. for (const propName of Object.keys(config.params)) {
  355. const value = config.params[propName];
  356. if (value !== null && typeof (value) !== "undefined") {
  357. if (value instanceof Array) {
  358. for (const key of Object.keys(value)) {
  359. let params = propName + '[' + key + ']';
  360. config.params[params] = value[key]
  361. }
  362. delete config.params[propName]
  363. }
  364. }
  365. }
  366. }
  367. const routeData = this.$router.resolve({
  368. path: '/api/blade-client/partsCorps/export-desc', //跳转目标窗口的地址
  369. query: {
  370. ...config.params, //括号内是要传递给新窗口的参数
  371. identification: this.url
  372. }
  373. })
  374. window.open(routeData.href.slice(1, routeData.href.length) + '&' + `${this.website.tokenHeader}=${getToken()}`);
  375. },
  376. uploadBefore(file, done, loading) {
  377. done();
  378. loading = true;
  379. },
  380. uploadAfter(res, done, loading, column) {
  381. this.excelBox = false;
  382. let myError = res.toString();//转字符串
  383. myError = myError.replace("Error: ", "") // 去掉前面的" Error: "
  384. this.$message.success(myError);
  385. this.refreshChange();
  386. loading = false;
  387. done();
  388. },
  389. filterNode(value, data) {
  390. console.log(value, data)
  391. if (!value) return true;
  392. return data.label.indexOf(value) !== -1;
  393. },
  394. nodeClick(data) {
  395. this.search.corpsTypeId = data.value
  396. this.page.currentPage = 1;
  397. this.onLoad(this.page, this.search);
  398. },
  399. getAllWorkDicts() {
  400. //状态
  401. // this.getWorkDicts("client_status").then(res => {
  402. // this.findObject(this.option.column, "status").dicData = res.data.data;
  403. // });
  404. getCorpType({ corpType: 'KH' }).then(res => {
  405. this.treeData = res.data.data
  406. });
  407. // customerList({ corpType: "KH" }).then(res => {
  408. // this.findObject(this.option4.column, "parentId").dicData = res.data.data.records
  409. // });
  410. this.$refs.crud.init();
  411. },
  412. searchCriteriaSwitch(type) {
  413. if (type) {
  414. this.option.height = this.option.height - 46;
  415. } else {
  416. this.option.height = this.option.height + 46;
  417. }
  418. this.$refs.crud.getTableHeight();
  419. },
  420. cellStyle() {
  421. return "padding:0;height:40px;";
  422. },
  423. //点击搜索按钮触发
  424. searchChange(params, done) {
  425. this.page.currentPage = 1;
  426. this.onLoad(this.page, params);
  427. done();
  428. },
  429. refreshChange() {
  430. this.onLoad(this.page, this.search);
  431. },
  432. newAdd() {
  433. this.show = false;
  434. },
  435. onLoad(page, params = {}) {
  436. let data = this.deepClone(Object.assign(params, this.search));
  437. if (data.date && data.date.length > 0) {
  438. data.startTime = data.date[0]
  439. data.endTime = data.date[1]
  440. }
  441. delete data.date
  442. data.corpType = "GYS"
  443. this.loading = true;
  444. getList(
  445. page.currentPage,
  446. page.pageSize,
  447. data
  448. )
  449. .then(res => {
  450. this.dataList = res.data.data.records ? res.data.data.records : [];
  451. this.page.total = res.data.data.total;
  452. })
  453. .finally(() => {
  454. pageStatistics(data).then(res => {
  455. this.form = res.data.data
  456. })
  457. this.loading = false;
  458. });
  459. },
  460. addCorpType() {
  461. // this.$refs["corpType"].validate((valid, done) => {
  462. // done();
  463. // if (valid) {
  464. // addCorpType({ ...this.form4, corpType: 'KH', status: 0 })
  465. // .then(res => {
  466. // this.$message.success("保存成功");
  467. // this.getAllWorkDicts()
  468. // this.corpTypeVisible = false
  469. // })
  470. // } else {
  471. // return false;
  472. // }
  473. // });
  474. this.getAllWorkDicts()
  475. this.corpTypeVisible = false
  476. },
  477. corpTypeClosed() {
  478. // this.reload = Math.random();
  479. // this.form4 = this.$options.data().form4
  480. },
  481. viewInfo(row) {
  482. this.show = true;
  483. this.detailData = {
  484. id: row.id,
  485. };
  486. this.showInfo = false;
  487. },
  488. editOpen(row, status) {
  489. this.showInfo = true;
  490. this.detailData = {
  491. id: row.id,
  492. status: status
  493. };
  494. this.show = false;
  495. },
  496. currentChange(val) {
  497. this.page.currentPage = val;
  498. },
  499. sizeChange(val) {
  500. this.page.currentPage = 1;
  501. this.page.pageSize = val;
  502. },
  503. rowDel(row, index, done) {
  504. this.$confirm("确定删除数据?", {
  505. confirmButtonText: "确定",
  506. cancelButtonText: "取消",
  507. type: "warning"
  508. }).then(() => {
  509. remove({ id: row.id, corpType: "KH" }).then(res => {
  510. if (res.data.code == 200) {
  511. this.$message({
  512. type: "success",
  513. message: "删除成功!"
  514. });
  515. this.onLoad(this.page, this.search);
  516. }
  517. });
  518. });
  519. },
  520. async saveColumn() {
  521. const inSave = await this.saveColumnData(
  522. this.getColumnName(277.2),
  523. this.option
  524. );
  525. if (inSave) {
  526. this.$nextTick(() => {
  527. this.$refs.crud.doLayout();
  528. });
  529. this.$message.success("保存成功");
  530. //关闭窗口
  531. this.$refs.crud.$refs.dialogColumn.columnBox = false;
  532. }
  533. },
  534. async resetColumn() {
  535. this.option = option;
  536. const inSave = await this.delColumnData(this.getColumnName(277.2), option);
  537. if (inSave) {
  538. this.$nextTick(() => {
  539. this.$refs.crud.doLayout();
  540. });
  541. this.getAllWorkDicts()
  542. this.$message.success("重置成功");
  543. this.$refs.crud.$refs.dialogColumn.columnBox = false;
  544. }
  545. },
  546. //返回列表
  547. goBack() {
  548. this.detailData = this.$options.data().detailData;
  549. this.show = true;
  550. this.showInfo = true;
  551. this.onLoad(this.page, this.search);
  552. this.$nextTick(() => {
  553. this.$refs.crud.doLayout();
  554. });
  555. },
  556. }
  557. }
  558. </script>
  559. <style lang="scss" scoped>
  560. .page-crad ::v-deep .basic-container__card {
  561. height: 94.2vh;
  562. }
  563. ::v-deep .el-form-item__error {
  564. display: none !important;
  565. }
  566. ::v-deep .el-input-group__append {
  567. padding: 0 0px !important;
  568. }
  569. .el-dialog ::v-deep .el-form-item__error {
  570. display: none !important;
  571. }
  572. .stat-td {
  573. text-align: center;
  574. position: relative;
  575. }
  576. .stat-img {
  577. width: 95%;
  578. height: 100px;
  579. }
  580. .stat-tip {
  581. position: absolute;
  582. left: 15px;
  583. top: 5px;
  584. .money {
  585. color: #fff;
  586. font-size: 28px;
  587. text-align: left;
  588. font-weight: 600;
  589. }
  590. .title {
  591. color: #fff;
  592. font-size: 14px;
  593. text-align: left;
  594. margin-top: 5px;
  595. margin-bottom: 0px;
  596. }
  597. }
  598. </style>